现代操作系统应用开发:UWP——自适应界面Adaptive UI(二)

功能简介

  • 当你看这篇博客的时候,我就假设你已经看过了第一篇博客或者对UWP的自适应界面已经有了一定的了解了;UWP的自适应界面很强大,但是,UWP的自适应界面存在这样的限制,那就是如果你要设置一个控件自适应变换,你就必须给它声明x:Name;
  • 如果我们使用ListView的数据绑定(PS:如果不了解数据绑定,请跳转),那么对于ListView.ItemTemplate里的控件,我们就不能通过声明x:Name绑定到Target上,如下面代码所示
<!-- MainPage.xaml -->
<!-- ItemSource用于指定ListView的数据源,这里的Array为MainPage.xml.cs中MainPage类的一个集合 -->
<ListView Margin="20,20,50,20" ItemsSource="{x:Bind Array}" x:Name="MyList">
    <ListView.ItemTemplate>
        <!-- DataType指定Array中对象的类型,这里的Item为我们自定义的一个类 -->
        <DataTemplate x:DataType="local:Item">
            <!--
                这里的ListView对应的模板为一个Checkbox,一个Grid(用于分隔开CheckBox和TextBlock)
                一个Imag,还有一个文本框
            -->
            <RelativePanel>
                <CheckBox  HorizontalAlignment="Left" VerticalAlignment="Top" FontSize="14" CharacterSpacing="0" Margin="10,10,0,0"></CheckBox>
                <!-- 
                    在宽屏状态下,Space的宽度为90,这时候文本框和Checkbox中间存在的空间正好存放图片
                    在窄屏状态下,Space的宽度为0,此时图片隐藏,Checkbox后紧跟着文本框
                -->
                <Grid Width="90" x:Name="Space"></Grid>
                <Image  HorizontalAlignment="Left" Height="40" Margin="50,10,0,0" VerticalAlignment="Top" Width="40" Source="{x:Bind Source}" x:Name="MyImage"></Image>
                <TextBlock Text="{x:Bind Content}"  RelativePanel.RightOf="Space" VerticalAlignment="Top" HorizontalAlignment="Left" FontSize="20" Margin="10,12,0,0"></TextBlock>
            </RelativePanel>
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>
  • 如果我们想要在窗口较大的时候显示图片, 而窗口变小的时候隐藏图片,按照之前的方法,我们会发现,即使是在Setter中声明了MyImage.Visibility的Value为Collapsed,图片也不会隐藏
  • 所以这篇博客就是探讨在这种情况下如何实现图片的自适应变化

实现效果

  • 宽屏状态下:

  • 窄屏状态下:

实现过程

在MainPage.xml中创建需要的控件

这里添加的代码就是上面xaml代码,将上述代码添加到 MainPage.xaml里

添加一个新的类Item

位置:解决方案资源管理器—>添加—>新建项—>Visual C#—>代码—>类

在新建的Item.cs文件中添加下面的代码:

//Item.cs
//AdaptiveUIWithListView为你自己所使用的命名空间,
namespace AdaptiveUIWithListView
{
    public class Item
    {
        private string _content;
        private string _source;
        //封装
        public string Content { get => _content; }
        public string Source { get => _source; }
        //构造函数
        public Item(string content, string source)
        {
            this._content = content;
            this._source = source;
        }
    }
}

需要注意的是,这里的AdaptiveUIWithListView为博客的项目所使用的命名空间,你也可以使用自己定义的命名空间

但是如果你使用了自己定义的命名空间,因为MainPage.xaml.cs和MainPage.xaml里都使用了Item,所以需要添加using指令

假如你的Item使用的命名空间为MyNamespace,那么:

  • 首先需要在MainPage.xaml.cs里添加using MyNamespace;
  • 其次,在xaml前几行的Page属性里添加xmlns:mynamespace=”using:MyNamespace” 和DataTemplate的x:DataType=”local:Item”更改为x:DataType=”mynamespace:Item” (这里的mynamespace可以更改为你自己想要的值)

在构造函数上添加函数监听窗口尺寸变化和添加Array这一属性值

//MainPage.xaml.cs
//ObservableCollection一般用于数据绑定的Sourc
public ObservableCollection<Item> Array = new ObservableCollection<Item>();
public MainPage()
{
    //往Array中添加元素
    Array.Add(new Item("This is the head line, with the pictur 0.png in Folder /Assets.", "Assets/0.png"));
    Array.Add(new Item("This is the first line, with the pictur 1.png in Folder /Assets.", "Assets/1.png"));
    Array.Add(new Item("This is the second line, with the pictur 2.png in Folder /Assets.", "Assets/2.png"));
    Array.Add(new Item("This is the third line, with the pictur 3.png in Folder /Assets.", "Assets/3.png"));
    Array.Add(new Item("This is the fourth line, with the pictur 4.png in Folder /Assets.", "Assets/4.png"));
    this.InitializeComponent();

    //监听窗口大小变化事件
    this.SizeChanged += (s, e) =>
    {
        if (e.NewSize.Width > 000 && e.NewSize.Width < 600)
        {
            //ShowImage为自定义的函数,见第四步
            ShowImage(false);
        }
        else
        {
            ShowImage(true);
        }
    };
}

定义ShowImage函数

//flag决定图片是否显示
private void ShowImage(bool flag)
{
    /*
     * FindChildren是一个自定义的函数,接受两个参数,一个是List<T>,另一个是窗口的一个控件
     * FindChildren运行结束后,将找到该控件的所有子控件中类型为T的控件
     * 下面的例子即找到MyList控件中所有类型为RelativePanel的控件
     */
    List<RelativePanel> list = new List<RelativePanel>();
    FindChildren<RelativePanel>(list, MyList);

    foreach (RelativePanel panel in list)
    {
        for (int i = 0; i < panel.Children.Count; i++)
        {
            //如果为图片,则判断是否显示
            if (panel.Children[i] is Image)
            {
                if (flag)
                {
                    ((Image)panel.Children[i]).Visibility = Visibility.Visible;
                }
                else
                {
                    ((Image)panel.Children[i]).Visibility = Visibility.Collapsed;
                }
            }
            //这里的Grid即xaml中的Space
            if (panel.Children[i] is Grid)
            {
                if (flag)
                {
                    ((Grid)panel.Children[i]).Width = 90;
                }
                else
                {
                    ((Grid)panel.Children[i]).Width = 40;
                }
            }
        }
    }
}

//遍历startNode的子节点,找到类型为T的控件并且放在results中
internal static void FindChildren<T>(List<T> results, DependencyObject startNode)
    where T : DependencyObject
        {
            int count = VisualTreeHelper.GetChildrenCount(startNode);
            for (int i = 0; i < count; i++)
            {
                DependencyObject current = VisualTreeHelper.GetChild(startNode, i);
                if ((current.GetType()).Equals(typeof(T)) || (current.GetType().GetTypeInfo().IsSubclassOf(typeof(T))))
                {
                    T asType = (T)current;
                    results.Add(asType);
                }
                FindChildren<T>(results, current);
            }
        }

总结

最后总结一下,整个图片隐藏的过程就是:

Created with Raphaël 2.1.2 SizeChanged函数监听窗口变化 设置flag的值 showImage接收flag Findchildren找到所有的RelativePanel 根据flag设置RelativePanel里的图片是否隐藏

FYI

其实,之前我还尝试过另一种方法,就是添加自定义控件UserControl的方法,然后在UserControl里设置VisualStateManager的Setter,然后再ListView里RelativePanel替换为

<UserControl>
     ......
</UserControl>

这样确实能实现图片的自动隐藏,但是却有出现另一个问题:Item的传值问题

如果使用UserControl,那么Item的属性值就必须传递给UserControl,在Debug模式下,我观察到Item的属性值确确实实已经传递给UserControl,但是UserControl的控件却没有显示出来,所以我想可能是UserControl先渲染出控件,然后才接收Item传递过来的值

如果有好的解决方法,欢迎在下面评论或者邮件(侧边栏点开就能找到了)ᕕ( ՞ ᗜ ՞ )ᕗ

项目下载:AdaptiveUIWithListView

项目下载之后记住把Debug模式从ARM换成X86或X64(根据你自己的机型选择),之前一开始学习的时候不知道这一点,从网上下载下来的项目都运行不了,纠结的一逼(╥╯^╰╥)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值