第二十六章:自定义布局(十三)

简介: Layout和LayoutToVisualElement定义了一组转换属性。这些是AnchorX,AnchorY,Rotation,RotationX,RotationY,Scale,TranslationX和TranslationY,它们根本不影响布局。

Layout和LayoutTo
VisualElement定义了一组转换属性。这些是AnchorX,AnchorY,Rotation,RotationX,RotationY,Scale,TranslationX和TranslationY,它们根本不影响布局。换句话说,设置这些属性不会生成对InvalidateMeasure或InvalidateLayout的调用。从GetSizeRequest返回的元素大小不受这些属性的影响。布局调用大小和位置元素,就好像这些属性不存在一样。
这意味着您可以为这些属性设置动画,而不会生成一堆布局循环。在ViewExtensions中定义为扩展方法的TranslateTo,ScaleTo,RotateTo,RotateXTo和RotateYTo动画方法完全独立于布局。
但是,ViewExtensions还定义了一个名为LayoutTo的方法,该方法对Layout方法进行动画调用。这会导致更改元素相对于其父元素的布局大小或位置,并设置元素的Bounds,X,Y,Width和Height属性的新值。
因此,使用LayoutTo需要采取一些预防措施。
例如,假设一个元素是StackLayout的子元素。当StackLayout获取LayoutChildren调用时,它将调用该元素上的Layout来调整大小并将其定位在相对于自身的特定位置。假设您的程序然后在该元素上调用LayoutTo以赋予它新的大小和位置。 StackLayout不知道这一点,所以如果StackLayout经历另一个布局周期,它会将元素移回它认为应该的位置。如果您仍然需要将元素放在StackLayout认为应该的位置之外的其他位置,您可能希望将处理程序附加到StackLayout的LayoutChanged事件并调用Layout或再次对该元素运行LayoutTo动画。
另一个问题是在具有许多子项的布局上运行LayoutTo动画。当然,这是允许的,但请记住,布局将获得对其Layout方法的大量调用,因此在动画正在进行时也会调用LayoutChildren方法。对于每个对LayoutChildren覆盖的调用,布局类将尝试布置其所有子代(当然,其中一些子代可能是带子代的其他布局),并且动画可能会变得非常不稳定。
但是您可以使用LayoutTo动画和Layout方法之间的关系来实现一些有趣的效果。元素必须将其Layout方法调用为在屏幕上可见,但调用LayoutTo必须满足该要求。
这是一个派生自CartesianLayout的类,名为AnimatedCartesianLayout。它定义了两个可绑定属性(不附加可绑定属性)来控制动画,而不是调用Layout并设置Rotation属性,它调用LayoutTo和(可选)RotateTo:

namespace Xamarin.FormsBook.Toolkit
{
    public class AnimatedCartesianLayout : CartesianLayout
    {
        public static readonly BindableProperty AnimationDurationProperty =
            BindableProperty.Create(
                "AnimatedDuration",
                typeof(int),
                typeof(AnimatedCartesianLayout),
                1000);
        public int AnimationDuration
        {
            set { SetValue(AnimationDurationProperty, value); }
            get { return (int)GetValue(AnimationDurationProperty); }
        }
        public static readonly BindableProperty AnimateRotationProperty =
            BindableProperty.Create(
                "AnimateRotation",
                typeof(bool),
                typeof(AnimatedCartesianLayout),
                true);
        public bool AnimateRotation
        {
            set { SetValue(AnimateRotationProperty, value); }
            get { return (bool)GetValue(AnimateRotationProperty); }
        }
        protected override void LayoutChildren(double x, double y, double width, double height)
        {
            foreach (View child in Children)
            {
                if (!child.IsVisible)
                    continue;
                double angle;
                Rectangle bounds = GetChildBounds(child, x, y, width, height, out angle);
                // Lay out the child.
                if (child.Bounds.Equals(new Rectangle(0, 0, -1, -1)))
                {
                    child.Layout(new Rectangle(x + width / 2, y + height / 2, 0, 0));
                }
                child.LayoutTo(bounds, (uint)AnimationDuration);
                // Rotate the child.
                if (AnimateRotation)
                {
                    child.RotateTo(angle, (uint)AnimationDuration);
                }
                else
                {
                    child.Rotation = angle;
                }
            }
        }
    }
}

唯一棘手的部分涉及一个尚未收到第一个布局调用的孩子。 这样的子项的Bounds属性是矩形(0,0,-1,-1),LayoutTo动画将使用该值作为动画的起始点。 在这种情况下,LayoutChildren方法首先调用Layout以将子项定位在中心并为其指定大小(0,0)。
AnimatedUnitCube程序的XAML文件几乎与UnitCube程序相同,但AnimatedCartesianLayout的动画持续时间为3秒:

<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:toolkit=
                 "clr-namespace:Xamarin.FormsBook.Toolkit;assembly=Xamarin.FormsBook.Toolkit"
             x:Class="AnimatedUnitCube.AnimatedUnitCubePage">
 
    <toolkit:AnimatedCartesianLayout BackgroundColor="Yellow"
             AnimationDuration="3000"
             HorizontalOptions="Center"
             VerticalOptions="Center">
        <toolkit:AnimatedCartesianLayout.Resources>
            <ResourceDictionary>
                <Style x:Key="baseStyle" TargetType="BoxView">
                    <Setter Property="Color" Value="Blue" />
                    <Setter Property="toolkit:CartesianLayout.Thickness" Value="3" />
                </Style>
                <Style x:Key="hiddenStyle" TargetType="BoxView"
                       BasedOn="{StaticResource baseStyle}">
                    <Setter Property="Opacity" Value="0.25" />
                </Style>
                <!-- Implicit style. -->
                <Style TargetType="BoxView"
                       BasedOn="{StaticResource baseStyle}" />
 
            </ResourceDictionary>
        </toolkit:AnimatedCartesianLayout.Resources>
        __
 
    </toolkit:AnimatedCartesianLayout>
</ContentPage>

以下屏幕截图显示了从左到右几乎到多维数据集完成点的进度:
2019_05_26_163549
根据它们的定义方式,某些水平线根本不会旋转,而其他水平线(例如底部的水平线)必须旋转180度。
如您所知,近年来用户界面变得更加生动和动态,因此使用LayoutTo而不是Layout来探索各种可能的技术可以成为冒险程序员追求的全新领域。

目录
相关文章
|
Android开发
Android开发布局 案例一
Android开发布局 案例一
131 0
Android开发布局 案例一
|
XML Java Android开发
Android开发布局 案例二
Android开发布局 案例二
215 0
Android开发布局 案例二
|
JavaScript Android开发
第二十六章:自定义布局(十一)
重叠的子项Layout 类可以在其子项上调用Layout方法,以便子项重叠吗?是的,但这可能会在你的脑海中提出另一个问题:什么决定孩子们的呈现顺序?哪些孩子看似坐在前台,可能部分或完全掩盖了背景中显示的其他孩子?在某些图形环境中,程序员可以访问名为Z-index的值。
648 0
|
JavaScript Android开发
第二十六章:自定义布局(十二)
更多附加的可绑定属性附加的可绑定属性也可以在XAML中设置并使用Style设置。 为了了解它是如何工作的,让我们检查一个名为CartesianLayout的类,它模仿一个二维的,四象限的笛卡尔坐标系。
543 0
|
Android开发 数据格式 XML
Android项目实战(二十):浅谈ListView悬浮头部展现效果
原文:Android项目实战(二十):浅谈ListView悬浮头部展现效果   先看下效果:需求是 滑动列表 ,其中一部分视图(粉丝数,关注数这一部分)在滑动到顶端的时候不消失,而是停留在整个界面头部。
1106 0
|
Android开发
Android项目实战(十五):自定义不可滑动的ListView和GridView
原文:Android项目实战(十五):自定义不可滑动的ListView和GridView 不可滑动的ListView (RecyclweView类似) public class NoScrollListView extends ListView { public NoScrollLi...
972 0
|
容器 算法 Java
GEF常见问题5:自动布局
利用自动布局功能,我们可以把本来不包含图形信息的文件以图形化的方式展示出来,典型的例子比如将一组Java接口反向工程为类图,那么图中每个图元的坐标应该必须都是自动生成的。GEF里提供了DirectedGraphLayout类用来实现自动布局功能,下面介绍一下怎样在程序里使用它。
1463 0
|
开发框架 移动开发
|
XML Android开发 数据格式
【Android开发学习笔记之一】5大布局方式详解
Android中常用的5大布局方式有以下几种: 线性布局(LinearLayout):按照垂直或者水平方向布局的组件。 帧布局(FrameLayout):组件从屏幕左上方布局组件。 表格布局(TableLayout):按照行列方式布局组件。
1310 0