ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]

原贴地址

前言:今天看到掘金上有一篇翻译的文章,看着看着发现只翻译到第二篇了,碰巧今天有时间,然后就翻译一下。

WOW,我又有了一天空闲时间所以现在可以开始学习一点新的极好的东西了。

Hi,各位基佬们,希望你们干♂的都不错呦→_→。我们已经在part1和part2学习到许多关于ConstraintLayout的许多新知识。现在可以开始学习关于这种极好的布局剩下的知识了。这也可能是关于ConstraintLayout的最后一篇文章了。

动机

写这篇文章的动机和你们在part1中讨论的一样。在这篇文章中我关注的重点会在ConstraintLayout的动画上面。一个坏消息是关于这个话题在android的文档上面没有太多的帮助。在开始这篇文章之前我要向各位基佬道个歉:由于我知识的匮乏所以我可能会在某些观念的角度上犯一些错误,但是我会给你们100%的保证最后会你根据我的观点舒♂服的享受这些动画。

关于这个标题我还是有一点疑惑的。所以我决定取三个名字:Constraint Layout Animations,Constraint Layout Dynamic Constraints和 用Java控制Constraint Layout UI。在这篇文章的最后,你就会知道为什么我会选择这三个名字了。

现在我会解释ConstraintLayout动画API提供的特征而不是分享你未来实现的时候将会遇到的问题。So its time to ATTACK :).

我们需要下载 2.3 版本的 Android studio。先前版本的可视化编辑器不太完善,有时会在面板上显示错误的信息。所以下载 2.3 测试版本是非常重要的,该版本在我写这篇文章时已经可以获取到了。(PS:本段摘自part2)

介绍

在这一部分我们最多的是在Java方面努力但是在开始之前我会在这篇文章中解释一下所有东西是怎么工作的。

在这篇文章中我会一直用到上面的app。我有一个ConstraintLayout,其中一共有5个按钮。

Apply和Reset按钮就是用来开始和充值我们的动画的。其他三个按钮用来应用我们的动画。我们将会给这三个按钮设置不同的动画。最重要的一点:我们在开始前就应该知道这三个按钮的约束(constraints)。





    

当你检查完代码之后你就会轻易的发现这三个按钮之间的关系但是为了方便我们还是看下面这张图吧。

HiaHiaHia,我知道对照着XML来看的话非常简单。现在你知道了这三个按钮之间的关系以及和父布局的关系。

在我们深度探♂索之前我想再解释一些新的API。

public class MainActivity extends AppCompatActivity {

private ConstraintLayout constraintLayout;
private ConstraintSet applyConstraintSet = new ConstraintSet();
private ConstraintSet resetConstraintSet = new ConstraintSet();

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    constraintLayout = (ConstraintLayout) findViewById(R.id.main);
    resetConstraintSet.clone(constraintLayout);
    applyConstraintSet.clone(constraintLayout);
}

public void onApplyClick(View view) {

}

public void onResetClick(View view) {

}

注意加粗的那几行,其他的代码都很简单。ConstraintSet是我们在本次中会频繁用到的一个API。简单的说你可以认为这个API将会记住我们在XML中定义的所有约束。那么她是怎么实现的呢?就先你看到的那样,在上面的代码中我有一个constarintLayout而且之后我将其中的约束复制到了resetConstraintSet和applyConstraintSet中,非常简单。

现在开始因为新的需求来了所以我要改变我的代码格式了。黑人问号.jpg

我将会用不同的实现方式来满足需求,在其中你会非常同意的明白我这篇文章的标题。

新需求:

我想让当用户点击Apply按钮的时候button1动起来和父布局的左边对齐。

用开发语言来说:

Hi,基♂佬。用户点击Apply按钮的时候我要用Java代码使用ConstraintLayout让button1和父布局左边对齐。你能帮我吧?

解决办法:

public void onApplyClick(View view) {
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,8);
    applyConstraintSet.applyTo(constraintLayout);
}

public void onResetClick(View view) {
    resetConstraintSet.applyTo(constraintLayout);
}

之后我会只讲解onApplyClick()方法,其他的代码基本相同。Oh,我忘记了onResetClick()方法,在其中我总是将原始的约束赋给我最开始的UI。

现在有两个新的API方法:setMargin()和applyTo(),我感觉applyTo()不需要解释了吧。

setMargin()方法有三个参数(viewId, anchor, margin).(PS:个人理解是viewId赋到哪个View上,anchor是对齐方式,margin是间隔)

Button1的left margin原来有52dp,但是当用户点击之后就变成了8px。让我们来看看效果如何。

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第1张图片

Oh no!按钮看起来像是跳跃一样的移动的,根本就不像是动画。这样很不好所以我们需要重新审视一下我们的代码。

—-。在重新检查过之后我发现我需要在applyButton()中添加一行代码。在我添加完那一行代码之后我发现她变成了下边这个样子。

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第2张图片

完成!现在我们回顾一下刚才改动了啥。

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,8);
    applyConstraintSet.applyTo(constraintLayout);
}

在这里我需要添加TransitionManager的API。这里有一个关于TransitionManager的API可用的依赖库,你可以添加到你的gradle依赖中:

compile 'com.android.support:transition:25.1.0'

在我们开始实现接下来的需求之前,我要先回顾一下。

总结起来就是我们使用了两个API分别是ConstraintSet和TransitionManager。从现在开始我们就只关注ConstraintSet这一个API了。

新需求

以用户的语言来说:当用户点击Apply按钮的时候我想让所有按钮在父布局中水平居中。

以开发者的语言来说:Hey,基佬。我想,,,当用户点击Apply按钮的时候我要用Java代码使用ConstraintLayout让所有按钮在父布局中水平居中。你能帮我吧?

解决办法:

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);
    applyConstraintSet.centerHorizontally(R.id.button1, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button2, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button3, R.id.main);
    applyConstraintSet.applyTo(constraintLayout);
}

在这里我用到了centerHorizontally()方法。这个方法有两个参数:

    第一个:我想要水平居中的那个View

    第二个:到哪个View上(PS:原文为to view,不知道这么翻译合不合适)

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第3张图片

OH,为什么还不是和我们想的一样。在我认真的分析过之后我找到了问题:我们在这三个button上有不同的margin导致了当我们点击Apply按钮的时候她们考虑到margin没有完全居中。所以现在到了解决这个问题的时候了。

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button1,ConstraintSet.END,0);
    applyConstraintSet.setMargin(R.id.button2,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button2,ConstraintSet.END,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.END,0);


    applyConstraintSet.centerHorizontally(R.id.button1, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button2, R.id.main);
    applyConstraintSet.centerHorizontally(R.id.button3, R.id.main);
    applyConstraintSet.applyTo(constraintLayout);
}

下面我把所有按钮的margin设置成0之后就完成了。

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第4张图片

新需求:

以用户的语言来说:当用户点击Apply按钮的时候我想让button3在父布局中居中。

以开发者的语言来说:Hey,基佬。我想要,,,当用户点击Apply按钮的时候我要用Java代码使用ConstraintLayout让button3在父布局中居中。。你能帮我吧?

解决办法:

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.START,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.END,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.TOP,0);
    applyConstraintSet.setMargin(R.id.button3,ConstraintSet.BOTTOM,0);

    applyConstraintSet.centerHorizontally(R.id.button3, R.id.main);
    applyConstraintSet.centerVertically(R.id.button3, R.id.main);

    applyConstraintSet.applyTo(constraintLayout);
}

下面是我第一次给四面的margin都设置为0然后我使用了centerHorizontal + centerVertical 方法。

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第5张图片

新需求:

以用户的语言来说:当用户点击Apply按钮的时候把所有的按钮宽度变成600px。

以开发者的语言来说:Hey,基佬。我想,,,用户点击Apply按钮的时候我要用Java代码使用ConstraintLayout让所有的按钮宽度变成600px。

解决方法:

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.constrainWidth(R.id.button1,600);
    applyConstraintSet.constrainWidth(R.id.button2,600);
    applyConstraintSet.constrainWidth(R.id.button3,600);

    // applyConstraintSet.constrainHeight(R.id.button1,100);
    // applyConstraintSet.constrainHeight(R.id.button2,100);
    // applyConstraintSet.constrainHeight(R.id.button3,100);

    applyConstraintSet.applyTo(constraintLayout);

}

下面就是我用constrainWidth方法的效果:

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第6张图片

新需求:

以用户的语言来说:当用户点击Apply按钮的时候让button1的宽和高铺满整个屏幕并且其他view隐藏。

以开发者的语言来说:Hi,基佬。当用户点击Apply按钮的时候我想用Java代码使用ConstraintLayout让button1 match_parent,match_parent并且其他View都隐藏。你能帮我吧。

解决办法:

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.setVisibility(R.id.button2,ConstraintSet.GONE);
    applyConstraintSet.setVisibility(R.id.button3,ConstraintSet.GONE);
    applyConstraintSet.clear(R.id.button1);
    applyConstraintSet.connect(R.id.button1,ConstraintSet.LEFT,R.id.main,ConstraintSet.LEFT,0);
    applyConstraintSet.connect(R.id.button1,ConstraintSet.RIGHT,R.id.main,ConstraintSet.RIGHT,0);
    applyConstraintSet.connect(R.id.button1,ConstraintSet.TOP,R.id.main,ConstraintSet.TOP,0);
    applyConstraintSet.connect(R.id.button1,ConstraintSet.BOTTOM,R.id.main,ConstraintSet.BOTTOM,0);
    applyConstraintSet.applyTo(constraintLayout);
}

在这里我想解释一下一些我上边用到的方法:

setVisibility: 我认为这个很简单
clear:我想清除掉view上的所有约束
connect:我想在一个view上添加约束,这个方法有5个参数:

    第一个:我想要加约束的那个View

    第二个:我想要加在哪个边界上

    第三个:锚点

    第四个:锚点的边界

    第五个:Margin

是时候进行一些深♂入的探索了。因为我们已经在part2中学习到了Chaining的概念。我将给你展示一下我们如何用JAVA来实现。(用开发者的语言)

新需求:

以用户的语言来说:当用户点击Apply按钮的时候我想让所有按钮互相对齐,排列在屏幕顶部而且水平居中。

以开发者的语言来说:Hi,基佬。我想要当用户点击Apply按钮的时候用Java代码使用ConstraintLayout让所有按钮互相对齐,排列在屏幕顶部而且水平居中。

解决方式:

我之前说的需要深♂入学习的东西但是我不会解释太多,所以你们要有心里准备。

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.clear(R.id.button1);
    applyConstraintSet.clear(R.id.button2);
    applyConstraintSet.clear(R.id.button3);

首先我清除掉三个按钮上的所有约束。其实你有好多种别的方式比如清除掉所有的margin和size来做到这种效果,但是我觉得这种方法是最简单的实现方式。现在我的按钮没有了任何的约束(0 width,0 height,0 margin…).

// button 1 left and top align to parent
applyConstraintSet.connect(R.id.button1, ConstraintSet.LEFT, R.id.main, ConstraintSet.LEFT, 0);

以上代码中我给button1加上了左边的约束。

// button 3 right and top align to parent
applyConstraintSet.connect(R.id.button3, ConstraintSet.RIGHT, R.id.main, ConstraintSet.RIGHT, 0);

以上代码中我给button3加上了右边的约束。

在你的脑中构建一下我们当前的button1在父布局的左上角并且button2紧随在button1的右上角。

// bi-direction or Chaining between button 1 and button 2
applyConstraintSet.connect(R.id.button2, ConstraintSet.LEFT, R.id.button1, ConstraintSet.RIGHT, 0);
applyConstraintSet.connect(R.id.button1, ConstraintSet.RIGHT, R.id.button2, ConstraintSet.LEFT, 0);

我在上边的代码中给button1和button2建立了一个双向的联系。

// bi-direction or Chaining between button 2 and button 3
applyConstraintSet.connect(R.id.button2, ConstraintSet.RIGHT, R.id.button3, ConstraintSet.LEFT, 0);
applyConstraintSet.connect(R.id.button3, ConstraintSet.LEFT, R.id.button2, ConstraintSet.RIGHT, 0);

我在上边的代码中给button2和button3建立了一个双向的联系。

applyConstraintSet.createHorizontalChain(R.id.button1,R.id.button3,new int[]{R.id.button1, R.id.button3},null, ConstraintWidget.CHAIN_PACKED);

这个方法为我们创建了一个横向的chain。这个方法有5个参数:

    第一个:chain中作为头部的view

    第二个:chain中作为尾部的view

    第三个:int数组,把首尾的view的id生成为一个数组。

    第四个:float数组,装有weight值,如果不想设置weight设置为null。

    第五个:像CHAIN_SPREAD一样的chaining 的样式。

现在如果我运行一下的话会是下面的这种结果。

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第7张图片

Oh no.这不是我想要的那种结果。如果你们记得我把这些buttons的所有约束都清除掉了,这就是为什么width和height是0。现在我需要像下边一样设置上width和height。

applyConstraintSet.constrainWidth(R.id.button1,ConstraintSet.WRAP_CONTENT);
applyConstraintSet.constrainWidth(R.id.button2,ConstraintSet.WRAP_CONTENT);
applyConstraintSet.constrainWidth(R.id.button3,ConstraintSet.WRAP_CONTENT);

applyConstraintSet.constrainHeight(R.id.button1,ConstraintSet.WRAP_CONTENT);
applyConstraintSet.constrainHeight(R.id.button2,ConstraintSet.WRAP_CONTENT);
applyConstraintSet.constrainHeight(R.id.button3,ConstraintSet.WRAP_CONTENT);

然后再次运行:

ConStraintLayout 动画|动态Constraints|用Java控制UI[第三部分]_第8张图片

快,现在到了给你们展示全部代码的时候了。

public void onApplyClick(View view) {
    TransitionManager.beginDelayedTransition(constraintLayout);

    applyConstraintSet.clear(R.id.button1);
    applyConstraintSet.clear(R.id.button2);
    applyConstraintSet.clear(R.id.button3);

    // button 1 left and top align to parent
    applyConstraintSet.connect(R.id.button1, ConstraintSet.LEFT, R.id.main, ConstraintSet.LEFT, 0);

    // button 3 right and top align to parent
    applyConstraintSet.connect(R.id.button3, ConstraintSet.RIGHT, R.id.main, ConstraintSet.RIGHT, 0);

    // bi-direction or Chaining between button 1 and button 2
    applyConstraintSet.connect(R.id.button2, ConstraintSet.LEFT, R.id.button1, ConstraintSet.RIGHT, 0);
    applyConstraintSet.connect(R.id.button1, ConstraintSet.RIGHT, R.id.button2, ConstraintSet.LEFT, 0);

    // bi-direction or Chaining between button 2 and button 3
    applyConstraintSet.connect(R.id.button2, ConstraintSet.RIGHT, R.id.button3, ConstraintSet.LEFT, 0);
    applyConstraintSet.connect(R.id.button3, ConstraintSet.LEFT, R.id.button2, ConstraintSet.RIGHT, 0);

    applyConstraintSet.createHorizontalChain(R.id.button1,R.id.button3,new int[]{R.id.button1,R.id.button3}, null, ConstraintWidget.CHAIN_PACKED);

    applyConstraintSet.constrainWidth(R.id.button1,ConstraintSet.WRAP_CONTENT);
    applyConstraintSet.constrainWidth(R.id.button2,ConstraintSet.WRAP_CONTENT);
    applyConstraintSet.constrainWidth(R.id.button3,ConstraintSet.WRAP_CONTENT);

    applyConstraintSet.constrainHeight(R.id.button1,ConstraintSet.WRAP_CONTENT);
    applyConstraintSet.constrainHeight(R.id.button2,ConstraintSet.WRAP_CONTENT);
    applyConstraintSet.constrainHeight(R.id.button3,ConstraintSet.WRAP_CONTENT);

    applyConstraintSet.applyTo(constraintLayout);
}

现在改变Chain的样式:

applyConstraintSet.createHorizontalChain(R.id.button1,R.id.button3,new int[]{R.id.button1, R.id.button3}, null, ConstraintWidget.CHAIN_SPREAD);

现在改变Chain的样式:

applyConstraintSet.createHorizontalChain(R.id.button1,R.id.button3,new int[]{R.id.button1, R.id.button3}, null, ConstraintWidget.CHAIN_SPREAD_INSIDE);

现在我给你展示一下CHAIN_PACKED with bias的样式

applyConstraintSet.createHorizontalChain(R.id.button1,R.id.button3,new int[]{R.id.button1, R.id.button3}, null, ConstraintWidget.CHAIN_PACKED);

applyConstraintSet.setHorizontalBias(R.id.button1, .1f);

在这里我使用了一个新的方法setHorizontalBias(),在其中我传递了chain的头和float类型的bias值。

奖励关卡:

我将给你展示在Android API中关于ConstraintSet的一个别的用法。基本上我们能在同一个ConstraintLayout应用两种不同的ConstraintSet,如下所示:

public class MainActivity extends AppCompatActivity {

    private ConstraintLayout constraintLayout;
    private ConstraintSet constraintSet1 = new ConstraintSet();
    private ConstraintSet constraintSet2 = new ConstraintSet();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        constraintLayout = (ConstraintLayout) findViewById(R.id.main);
        constraintSet1.clone(constraintLayout);
        constraintSet2.clone(this, R.layout.activity_main2);
    }

    public void onApplyClick(View view) {
        TransitionManager.beginDelayedTransition(constraintLayout);
        constraintSet2.applyTo(constraintLayout);
    }

    public void onResetClick(View view) {
        TransitionManager.beginDelayedTransition(constraintLayout);
        constraintSet1.applyTo(constraintLayout);
    }
}

XML of activity_main:





    

XML of activty_main2:





    

至此我们完成了ConstraintLayout Animations。接下来也是最后一个文章是:Constraint Layout Visual [Design] Editor ( What the hell is this )[Part4]。

是时候说再见了各位基佬们。祝你们过一个好的周末。

你可能感兴趣的:(学习总结)