zoukankan      html  css  js  c++  java
  • 博客园客户端UAP开发随笔 -- 适配不同尺寸的屏幕

    Windows 8诞生之初,Modern apps被设计在运行于全屏模式下。为了让Windows在运行Modern app时继续拥有前台多任务能力,Windows引入了一种全新的分屏技术“SnapView”。它允许将支持这种视图的Modern app贴在屏幕一边,以1/4 (实际上是逻辑分辨率宽度333左右)屏幕尺寸运行。这种视图特别适于工具类应用(如词典)和即时通讯类应用(如QQ)。分屏多任务也成了Windows 8区别于iPad和安卓Pad系统的重要特征。

    当时程序员在考虑Modern App适配不同视图和屏幕分辨率时,一般主要考虑Landscape View (FullScreenSize, Fill)、Portriat View和SnapView,以及一些常见的分辨率如1366*768、1920*1080等。

    可能是Windows的开发者们觉得仅仅是SnapView还不够,也可能是再次感悟到“Windows”的真谛,自Windows 10开始,Modern app允许以窗口形式运行。因此Modern app的窗口几乎可以是任何尺寸,Windows Store App的显示适配问题就需要再次拿出来聊聊了。

    一般来说,Modern app尺寸变化的判断和适配有以下4个时机:

    · VisualStateManager

    · DetermineVisualState

    · Window.SizeChanged

    · OnApplyTheme

    1. VisualStateManger 是最常用的方法,也是最方便的方法。它的用法也相对简单。先看一段XAML代码:

    <Page>
    <Grid x:Name=”LayoutGrid”>
    <VisualStateManager.VisualStateGroups>
                <!-- Visual states reflect the application's view state inside the FlipView -->
                <VisualStateGroup>
                    <VisualState x:Name="FullScreenLandscape"/>
                    <VisualState x:Name="Filled">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="AutoCompleteContainer" Storyboard.TargetProperty="Width">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="800"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
    
                    <VisualState x:Name="FullScreenPortrait">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SP_Main" Storyboard.TargetProperty="Orientation">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="Vertical"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
    
                    <VisualState x:Name="Snapped">
                        <Storyboard>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="NavigationBarContainer" Storyboard.TargetProperty="Visibility">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="Collapsed"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SV_Main" Storyboard.TargetProperty="Style">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="{StaticResource VerticalScrollViewerStyle}"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="SP_Main" Storyboard.TargetProperty="Orientation">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="Vertical"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="searchBarControl" Storyboard.TargetProperty="Margin">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="10,0,10,0"/>
                            </ObjectAnimationUsingKeyFrames>
                            <ObjectAnimationUsingKeyFrames Storyboard.TargetName="searchBarControl" Storyboard.TargetProperty="Width">
                                <DiscreteObjectKeyFrame KeyTime="0" Value="300"/>
                            </ObjectAnimationUsingKeyFrames>
                        </Storyboard>
                    </VisualState>
                </VisualStateGroup>
            </VisualStateManager.VisualStateGroups>
    </Grid>
    </Page>

    VisualStateManager代码位于Page的LayoutGrid下,以Storageboard的形式给出了不同视图下需要做的适配性变化。以“SnapView”为例,我们通常给予SnapView更多关照,如container宽度的调整,ScrollView方向的调整,一些辅助的显示控件的隐藏等等。值得欣慰的是,使用VisualStateManager的XAML代码,你只需要考虑怎么来的,不需要考虑怎么回去。当VisualState发生变化时,StateManager会先让视图回到初始状态,然后再执行新的变化。

    必应词典的SnapView就是用这种方式实现的:

    image

    2. DetermineVisualState

    DetermineVisualState像是VisualStateManager的C#版本,它是一个重载函数,用于继承了LayoutAwarePage的Page。来看一段代码:

    protected override string DetermineVisualState(ApplicationViewState viewState)
            {
                if (viewState == ApplicationViewState.Snapped)
                {
                    if (_DefinitionControl != null)
                    {
                        _DefinitionControl.SetToSnapStyle();
                    }
    
                    Grid_Layout.RowDefinitions[0].Height = new GridLength(60);
    ……
    ……
                }
                else
                {
    
                 if (_DefinitionControl != null)
                    {
                        _DefinitionControl.SetToLandscapeStyle();
                    }
    
                    Grid_Layout.RowDefinitions[0].Height = new GridLength(80);
                    // semanticZoom.IsZoomOutButtonEnabled = true;
    
                }
    …….
    ……
                return viewState.ToString();
            }

    在DetermineVisualState中,可以手动添加一些代码,做一些特殊处理,或者用VisualStateManager不容易表达的变化。但DetermineVisualState用起来就没有VisualStateManager那么方便了,要知道怎么来的,还要知道怎么回去。这里的代码应该尽可能的少一些。

    3. Window.Current.SizeChanged

    如果想更精细的控制窗口变化时的界面效果,可以抓住在Window. Current .SizeChanged这个时机:

    protected override void OnNavigatedTo(NavigationEventArgs e)
    {
                Window.Current.SizeChanged += Current_SizeChanged;
    }
    Protected override void OnNavigatedFrom(NavigationeventArgs e)
    {
            Window.Current.SizeChanged-=Current_SizeChanged;
    }
    
    void Current_SizeChanged(object sender, WindowSizeChangedEventArgs e)
    {
    //do something here            
    }

    4. OnApplyTheme

    在自定义控件显示前,OnApplyTheme是一个比较常用的函数用来灵活的给页面元素赋值、修改控件外观。举个”栗“子:

    protected override void OnApplyTemplate()
     {
                Grid layoutGrid = GetTemplateChild("Grid_Layout") as Grid;
                if (_counter % 2 == 0)
                    layoutGrid.Background = Application.Current.Resources["HomepageDataContainerBackground1"] as SolidColorBrush;
                else
                    layoutGrid.Background = Application.Current.Resources["HomepageDataContainerBackground2"] as SolidColorBrush;
    
                StackPanel SP_KeyWords = GetTemplateChild("SP_KeyWords") as StackPanel;
                int counter = 1;
                foreach (KeyWord keyWord in _DailyNews.KeyWords)
                {
                    KeyWordTile keyWordTile = new KeyWordTile(keyWord, counter);
                    keyWordTile.KeyWordClicked += dailyNewsTile_KeyWordTileClicked;
                    SP_KeyWords.Children.Add(keyWordTile);
                    counter++;
                }
    …. Do other things.
                base.OnApplyTemplate();
            }

    掌握了以上四点,相信大家都能做出看起来很美、适配广泛的的Modern App。

    分享代码,改变世界!

    Windows Phone Store App link:

    http://www.windowsphone.com/zh-cn/store/app/博客园-uap/500f08f0-5be8-4723-aff9-a397beee52fc

    Windows Store App link:

    http://apps.microsoft.com/windows/zh-cn/app/c76b99a0-9abd-4a4e-86f0-b29bfcc51059

    GitHub open source link:

    https://github.com/MS-UAP/cnblogs-UAP

    MSDN Sample Code:

    https://code.msdn.microsoft.com/CNBlogs-Client-Universal-477943ab

  • 相关阅读:
    MFC中获取系统当前时间
    我的定时关机程序(MFC实现) .
    编写一个闹钟和定时关机工具(MFC VS2010)
    Spark-SQL之DataFrame操作
    RDD操作
    Scala之Object (apply) dycopy
    Intellij IDEA 快捷键整理(dyCopy)
    python第三方包的windows安装文件exe格式
    pythong 中的 __call__
    触发器学习笔记(:new,:old用法)
  • 原文地址:https://www.cnblogs.com/ms-uap/p/4253419.html
Copyright © 2011-2022 走看看