精华内容
下载资源
问答
  • 尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所以在处理类似情况时,可以考虑使用函数节流函数解决,至于具体使用哪一种方式,根据实际情况分析定夺,先...

    我们都知道频繁触发执行一段js逻辑代码对性能会有很大的影响,尤其是在做一些效果实现方面,或者逻辑中需要进行后端请求,更是会导致卡顿,效果失效等结果,所以在处理类似的情况时,可以考虑使用函数节流和函数去抖来解决,至于具体使用哪一种方式,根据实际情况分析定夺,先来讲解一些这两者的概念,以下是我个人的一些看法,若有不足,希望大家可以提出.

    函数节流

    在频繁触发的情况下,需要执行的逻辑只有执行完之后,才能继续执行下一次.示例代码:

    // 函数节流例子
    var can = true;
    window.onscroll = function(){
      if(!can){
       //判断上次逻辑是否执行完毕,如果在执行中,则直接return
       return;
      }
      can = false;
      setTimeout(function(){
        //执行逻辑
        can = true;
      }, 100);
    };

    函数去抖

    在频繁触发的情况下,只有足够的空闲时间,才执行代码一次,如果没有执行完就清除掉,重新执行逻辑,示例代码:

    // 函数去抖
    var timer = null;
    window.onscroll = function(){
        if (timer) {
          // 清除未执行的逻辑,重新执行下一次逻辑,不论上一次是否执行完毕
          clearTimeout(timer); 
        }
        timer = setTimeout(function(){
            //执行逻辑
        }, 300);
    };
    

    应用场景

    一般是一些高频率触发的地方,然后想要优化性能.比如监听屏幕滚动,鼠标拖拽等等.

     

     

    展开全文
  • 在我刚毕业一年内,无论我怎么看委托事件都始终无法理解它原理,也不知道用到那里,就没有理它了。直到最近看了设计模式观察者模式演变成委托事件,我才真正恍然大悟。也明白了用在了什么地方。 在此...

    在我刚毕业的一年内,无论我怎么看委托和事件都始终无法理解它的原理,也不知道用到那里,就没有去理它了。直到最近看了设计模式的观察者模式演变成委托和事件,我才真正的恍然大悟。也明白了用在了什么地方。

    在此感谢TreeLee。让我懂了委托和事件的用处。灵感来源:http://www.cnblogs.com/Terrylee/archive/2006/10/23/Observer_Pattern.html

    下面利用某一个股票的价格的例子变动来阐述委托和事件。

     

    例子:一家证劵公司开发一个投资APP(如东方财富,同花顺),这个APP用来展示股票的价格的变动(不考虑买卖股票)。现在用某一股票(股票:TLA)的变动通知所有订阅了此股票的变动的投资者。

     

     

    这个抽象类有2个属性:股票和当前价格,1个方法(用来通知票价已变动),1个事件。

     1    public delegate void NotifyDelegate(object obj);
     2    public abstract class abstractAPP
     3     {
     4        //股票名字
     5         protected string product { get; set; }
     6 
     7        //股票价格
     8         protected int price { get; set; }
     9 
    10 
    11         public abstractAPP(string product, int price)
    12         {
    13             this.product = product;
    14             this.price = price;
    15         }
    16         public int Price 
    17         { 
    18             set { this.price=value;} 
    19             get {return price; }
    20         }
    21         public string  Product 
    22         { 
    23             set { this.product = value; }
    24             get { return product; } 
    25         }
    26 
    27        //定义一个委托的事件
    28         public NotifyDelegate NvfityEvent;
    29 
    30        //用来执行股票价格已经变动的通知
    31         public void Update()
    32         {
    33             Nvfity();
    34         }
    35 
    36         private void Nvfity()
    37         {
    38             if (NvfityEvent != null)
    39             {
    40                 NvfityEvent(this);
    41             }
    42         }
    43     }
    abstractAPP

     

    一个继承abstractAPP子类:

    1  public class APP:abstractAPP
    2     {
    3        public APP(string product, int price)
    4            : base(product, price)
    5         {
    6 
    7         }
    8     }
    APP

     

    投资者类:

     1  public class Investor
     2     {
     3         private string name;
     4         public Investor(string name)
     5         {
     6             this.name = name;
     7         }
     8 
     9 
    10         public void Receive(object obj)
    11         {
    12             if (obj is abstractAPP)
    13             {
    14                 var model = (abstractAPP)obj;
    15 
    16               Console.WriteLine("通知:{0} 股票:{1},当前股票价格:{2:C}", name, model.Product, model.Price);
    17                  
    18             }
    19         }
    20     }
    Investor

     

    移动设备端(也是用来接收通知):

     1  public class Mobile
     2     {
     3         private string no;
     4         public Mobile(string no)
     5         {
     6             this.no = no;
     7         }
     8 
     9         public void Receive(object obj)
    10         {
    11             if (obj is abstractAPP)
    12             {
    13                 var model = (abstractAPP)obj;
    14                 Console.WriteLine("{0}已接收到通知,产品:{1},价格:{2}", no,model.Product, model.Price);
    15             }
    16         }
    17     }
    Mobile

     

    Client端:

     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5 
     6 
     7 
     8             //初始值:股票名字:TLA,价格:12
     9             abstractAPP app = new APP("TLA", 12);
    10 
    11             //定义一个投资者对象,这个对象名叫mike
    12 
    13             //为了快捷一点就不抽象出父类出来了。
    14             Investor inverstor = new Investor("mike");
    15 
    16             Mobile mobile = new Mobile("vivoXX");
    17 
    18 
    19             //订阅了TLA股票的事件
    20             app.NvfityEvent += inverstor.Receive;
    21             app.NvfityEvent += mobile.Receive;
    22           
    23 
    24             //发起通知
    25             app.Update();
    26                 //TLA股票的价格变了
    27                 app.Price = 13;
    28 
    29                 Console.WriteLine();
    30                 //通知所有订阅者,股票价格改变了
    31                 Console.WriteLine("-------------价格变了!---------------------");
    32 
    33                 System.Threading.Thread.Sleep(1000);
    34                 Console.WriteLine();
    35                 Console.WriteLine("-------------发起通知!---------------------");
    36 
    37             //发起通知(告知所有订阅者)
    38                 app.Update();
    39 
    40 
    41                 app.Price = 12;
    42                 Console.WriteLine();
    43                 //再次通知所有订阅者,股票价格改变了
    44                 Console.WriteLine("-------------价格变了!---------------------");
    45 
    46                 System.Threading.Thread.Sleep(1000);
    47 
    48                 Console.WriteLine("-------------发起通知!---------------------");
    49                 Console.WriteLine();
    50                 //发起通知(告知所有订阅者)
    51                 app.Update();
    52 
    53                 //   Investor投资者已经卖掉了股票不在看此股票了,就不在订阅了
    54                 app.NvfityEvent -= inverstor.Receive;
    55 
    56 
    57                 //股票价格继续改动
    58                 Console.WriteLine();
    59                 app.Price = 11;
    60                 //再次通知所有订阅者,股票价格改变了
    61                 Console.WriteLine("-------------价格变了!---------------------");
    62 
    63                 System.Threading.Thread.Sleep(1000);
    64 
    65                 Console.WriteLine("-------------发起通知!---------------------");
    66                  //此时只有移动设备端订阅了此事件
    67                 Console.WriteLine();
    68                 app.Update();
    69 
    70          
    71             Console.ReadKey();
    72 
    73 
    74 
    75 
    76             
    77         }
    78     }
    Client

     

    转载于:https://www.cnblogs.com/kyle-jia/p/8038374.html

    展开全文
  • 包括ValueAnimatorObjectAnimator高级用法,那么除了这些之外,当然还有一些其它高级技巧在等着我们学习,因此本篇文章就对整个属性动画完全解析系列收个尾,学习一下剩下非常重要高级技巧。nterpolator...

    转载请注明出处:http://blog.csdn.net/guolin_blog/article/details/44171115


    大家好,欢迎继续回到Android属性动画完全解析。在上一篇文章当中我们学习了属性动画的一些进阶技巧,包括ValueAnimator和ObjectAnimator的高级用法,那么除了这些之外,当然还有一些其它的高级技巧在等着我们学习,因此本篇文章就对整个属性动画完全解析系列收个尾,来学习一下剩下的非常重要的高级技巧。


    另外,本篇文章中使用的代码是建立在上篇文章基础之上的,如果你还没有阅读过前面的文章,建议先去参考阅读一下 Android属性动画完全解析(中),ValueAnimator和ObjectAnimator的高级用法 。


    Interpolator的用法


    Interpolator这个东西很难进行翻译,直译过来的话是补间器的意思,它的主要作用是可以控制动画的变化速率,比如去实现一种非线性运动的动画效果。那么什么叫做非线性运动的动画效果呢?就是说动画改变的速率不是一成不变的,像加速运动以及减速运动都属于非线性运动。


    不过Interpolator并不是属性动画中新增的技术,实际上从Android 1.0版本开始就一直存在Interpolator接口了,而之前的补间动画当然也是支持这个功能的。只不过在属性动画中新增了一个TimeInterpolator接口,这个接口是用于兼容之前的Interpolator的,这使得所有过去的Interpolator实现类都可以直接拿过来放到属性动画当中使用,那么我们来看一下现在TimeInterpolator接口的所有实现类,如下图所示:




    可以看到,TimeInterpolator接口已经有非常多的实现类了,这些都是Android系统内置好的并且我们可以直接使用的Interpolator。每个Interpolator都有它各自的实现效果,比如说AccelerateInterpolator就是一个加速运动的Interpolator,而DecelerateInterpolator就是一个减速运动的Interpolator。


    我觉得细心的朋友应该早已经发现了,在前面两篇文章当中我们所学到的所有属性动画,其实都不是在进行一种线程运动。比如说在“上”篇文章中使用ValueAnimator所打印的值如下所示:




    可以看到,一开始的值变化速度明显比较慢,仅0.0开头的就打印了4次,之后开始加速,最后阶段又开始减速,因此我们可以很明显地看出这一个先加速后减速的Interpolator。


    那么再来看一下在“中”篇文章中完成的小球移动加变色的功能,如下图所示:



    从上图中我们明显可以看出,小球一开始运动速度比较慢,然后逐渐加速,中间的部分运动速度就比较快,接下来开始减速,最后缓缓停住。另外颜色变化也是这种规律,一开始颜色变化的比较慢,中间颜色变化的很快,最后阶段颜色变化的又比较慢。


    从以上几点我们就可以总结出一个结论了,使用属性动画时,系统默认的Interpolator其实就是一个先加速后减速的Interpolator,对应的实现类就是AccelerateDecelerateInterpolator。


    当然,我们也可以很轻松地修改这一默认属性,将它替换成任意一个系统内置好的Interpolator。就拿“中”篇文章中的代码来举例吧,MyAnimView中的startAnimation()方法是开启动画效果的入口,这里我们对Point对象的坐标稍做一下修改,让它变成一种垂直掉落的效果,代码如下所示:

    private void startAnimation() {
        Point startPoint = new Point(getWidth() / 2, RADIUS);
        Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.setDuration(2000);
        anim.start();
    }
    这里主要是对Point构造函数中的坐标值进行了一下改动,那么现在小球运动的动画效果应该是从屏幕正中央的顶部掉落到底部。但是现在默认情况下小球的下降速度肯定是先加速后减速的,这不符合物理的常识规律,如果把小球视为一个自由落体的话,那么下降的速度应该是越来越快的。我们怎样才能改变这一默认行为呢?其实很简单,调用Animator的setInterpolator()方法就可以了,这个方法要求传入一个实现TimeInterpolator接口的实例,那么比如说我们想要实现小球下降越来越快的效果,就可以使用AccelerateInterpolator,代码如下所示:
    private void startAnimation() {
        Point startPoint = new Point(getWidth() / 2, RADIUS);
        Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.setInterpolator(new AccelerateInterpolator(2f));
        anim.setDuration(2500);
        anim.start();
    }

    代码很简单,这里调用了setInterpolator()方法,然后传入了一个AccelerateInterpolator的实例,注意AccelerateInterpolator的构建函数可以接收一个float类型的参数,这个参数是用于控制加速度的。现在运行一下代码,效果如下图所示:




    OK,效果非常明显,说明我们已经成功替换掉了默认的Interpolator,AccelerateInterpolator确实是生效了。但是现在的动画效果看上去仍然是怪怪的,因为一个小球从很高的地方掉落到地面上直接就静止了,这也是不符合物理规律的,小球撞击到地面之后应该要反弹起来,然后再次落下,接着再反弹起来,又再次落下,以此反复,最后静止。这个功能我们当然可以自己去写,只不过比较复杂,所幸的是,Android系统中已经提供好了这样一种Interpolator,我们只需要简单地替换一下就可以完成上面的描述的效果,代码如下所示:

    private void startAnimation() {
        Point startPoint = new Point(getWidth() / 2, RADIUS);
        Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.setInterpolator(new BounceInterpolator());
        anim.setDuration(3000);
        anim.start();
    }

    可以看到,我们只是将设置的Interpolator换成了BounceInterpolator的实例,而BounceInterpolator就是一种可以模拟物理规律,实现反复弹起效果的Interpolator。另外还将整体的动画时间稍微延长了一点,因为小球反复弹起需要比之前更长的时间。现在重新运行一下代码,效果如下图所示:




    OK!效果还是非常不错的。那么这里我们只是选了几个系统实现好的Interpolator,由于内置Interpolator非常多,就不一一进行讲解了,大家可以自己去使用一下其它的几种Interpolator来看一看效果。


    但是,只会用一下系统提供好的Interpolator,我们显然对自己的要求就太低了,既然是学习属性动画的高级用法,那么自然要将它研究透了。下面我们就来看一下Interpolator的内部实现机制是什么样的,并且来尝试写一个自定义的Interpolator。


    首先看一下TimeInterpolator的接口定义,代码如下所示:

    /**
     * A time interpolator defines the rate of change of an animation. This allows animations
     * to have non-linear motion, such as acceleration and deceleration.
     */
    public interface TimeInterpolator {
    
        /**
         * Maps a value representing the elapsed fraction of an animation to a value that represents
         * the interpolated fraction. This interpolated value is then multiplied by the change in
         * value of an animation to derive the animated value at the current elapsed animation time.
         *
         * @param input A value between 0 and 1.0 indicating our current point
         *        in the animation where 0 represents the start and 1.0 represents
         *        the end
         * @return The interpolation value. This value can be more than 1.0 for
         *         interpolators which overshoot their targets, or less than 0 for
         *         interpolators that undershoot their targets.
         */
        float getInterpolation(float input);
    }

    OK,接口还是非常简单的,只有一个getInterpolation()方法。大家有兴趣可以通过注释来对这个接口进行详解的了解,这里我就简单解释一下,getInterpolation()方法中接收一个input参数,这个参数的值会随着动画的运行而不断变化,不过它的变化是非常有规律的,就是根据设定的动画时长匀速增加,变化范围是0到1。也就是说当动画一开始的时候input的值是0,到动画结束的时候input的值是1,而中间的值则是随着动画运行的时长在0到1之间变化的。


    说到这个input的值,我觉得有不少朋友可能会联想到我们在“中”篇文章中使用过的fraction值。那么这里的input和fraction有什么关系或者区别呢?答案很简单,input的值决定了fraction的值。input的值是由系统经过计算后传入到getInterpolation()方法中的,然后我们可以自己实现getInterpolation()方法中的算法,根据input的值来计算出一个返回值,而这个返回值就是fraction了。


    因此,最简单的情况就是input值和fraction值是相同的,这种情况由于input值是匀速增加的,因而fraction的值也是匀速增加的,所以动画的运动情况也是匀速的。系统中内置的LinearInterpolator就是一种匀速运动的Interpolator,那么我们来看一下它的源码是怎么实现的:

    /**
     * An interpolator where the rate of change is constant
     */
    @HasNativeInterpolator
    public class LinearInterpolator extends BaseInterpolator implements NativeInterpolatorFactory {
    
        public LinearInterpolator() {
        }
    
        public LinearInterpolator(Context context, AttributeSet attrs) {
        }
    
        public float getInterpolation(float input) {
            return input;
        }
    
        /** @hide */
        @Override
        public long createNativeInterpolator() {
            return NativeInterpolatorFactoryHelper.createLinearInterpolator();
        }
    }

    这里我们只看getInterpolation()方法,这个方法没有任何逻辑,就是把参数中传递的input值直接返回了,因此fraction的值就是等于input的值的,这就是匀速运动的Interpolator的实现方式。


    当然这是最简单的一种Interpolator的实现了,我们再来看一个稍微复杂一点的。既然现在大家都知道了系统在默认情况下使用的是AccelerateDecelerateInterpolator,那我们就来看一下它的源码吧,如下所示:

    /**
     * An interpolator where the rate of change starts and ends slowly but
     * accelerates through the middle.
     * 
     */
    @HasNativeInterpolator
    public class AccelerateDecelerateInterpolator implements Interpolator, NativeInterpolatorFactory {
        public AccelerateDecelerateInterpolator() {
        }
        
        @SuppressWarnings({"UnusedDeclaration"})
        public AccelerateDecelerateInterpolator(Context context, AttributeSet attrs) {
        }
        
        public float getInterpolation(float input) {
            return (float)(Math.cos((input + 1) * Math.PI) / 2.0f) + 0.5f;
        }
    
        /** @hide */
        @Override
        public long createNativeInterpolator() {
            return NativeInterpolatorFactoryHelper.createAccelerateDecelerateInterpolator();
        }
    }

    代码虽然没有变长很多,但是getInterpolation()方法中的逻辑已经明显变复杂了,不再是简单地将参数中的input进行返回,而是进行了一个较为复杂的数学运算。那这里我们来分析一下它的算法实现,可以看到,算法中主要使用了余弦函数,由于input的取值范围是0到1,那么cos函数中的取值范围就是π到2π。而cos(π)的结果是-1,cos(2π)的结果是1,那么这个值再除以2加上0.5之后,getInterpolation()方法最终返回的结果值还是在0到1之间。只不过经过了余弦运算之后,最终的结果不再是匀速增加的了,而是经历了一个先加速后减速的过程。我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:




    可以看到,这是一个S型的曲线图,当横坐标从0变化到0.2的时候,纵坐标的变化幅度很小,但是之后就开始明显加速,最后横坐标从0.8变化到1的时候,纵坐标的变化幅度又变得很小。


    OK,通过分析LinearInterpolator和AccelerateDecelerateInterpolator的源码,我们已经对Interpolator的内部实现机制有了比较清楚的认识了,那么接下来我们就开始尝试编写一个自定义的Interpolator。


    编写自定义Interpolator最主要的难度都是在于数学计算方面的,由于我数学并不是很好,因此这里也就写一个简单点的Interpolator来给大家演示一下。既然属性动画默认的Interpolator是先加速后减速的一种方式,这里我们就对它进行一个简单的修改,让它变成先减速后加速的方式。新建DecelerateAccelerateInterpolator类,让它实现TimeInterpolator接口,代码如下所示:

    public class DecelerateAccelerateInterpolator implements TimeInterpolator{
    
        @Override
        public float getInterpolation(float input) {
            float result;
            if (input <= 0.5) {
                result = (float) (Math.sin(Math.PI * input)) / 2;
            } else {
                result = (float) (2 - Math.sin(Math.PI * input)) / 2;
            }
            return result;
        }
    
    }

    这段代码是使用正弦函数来实现先减速后加速的功能的,因为正弦函数初始弧度的变化值非常大,刚好和余弦函数是相反的,而随着弧度的增加,正弦函数的变化值也会逐渐变小,这样也就实现了减速的效果。当弧度大于π/2之后,整个过程相反了过来,现在正弦函数的弧度变化值非常小,渐渐随着弧度继续增加,变化值越来越大,弧度到π时结束,这样从0过度到π,也就实现了先减速后加速的效果。


    同样我们可以将这个算法的执行情况通过曲线图的方式绘制出来,结果如下图所示:




    可以看到,这也是一个S型的曲线图,只不过曲线的方向和刚才是相反的。从上图中我们可以很清楚地看出来,一开始纵坐标的变化幅度很大,然后逐渐变小,横坐标到0.5的时候纵坐标变化幅度趋近于零,之后随着横坐标继续增加纵坐标的变化幅度又开始变大,的确是先减速后加速的效果。


    那么现在我们将DecelerateAccelerateInterpolator在代码中进行替换,如下所示:

    private void startAnimation() {
        Point startPoint = new Point(getWidth() / 2, RADIUS);
        Point endPoint = new Point(getWidth() / 2, getHeight() - RADIUS);
        ValueAnimator anim = ValueAnimator.ofObject(new PointEvaluator(), startPoint, endPoint);
        anim.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                currentPoint = (Point) animation.getAnimatedValue();
                invalidate();
            }
        });
        anim.setInterpolator(new DecelerateAccelerateInterpolator());
        anim.setDuration(3000);
        anim.start();
    }

    非常简单,就是将DecelerateAccelerateInterpolator的实例传入到setInterpolator()方法当中。重新运行一下代码,效果如下图所示:




    OK!小球的运动确实是先减速后加速的效果,说明我们自定义的Interpolator已经可以正常工作了。通过这样一个程度的学习,相信大家对属性动画Interpolator的理解和使用都达到了一个比较深刻的层次了。


    ViewPropertyAnimator的用法


    ViewPropertyAnimator其实算不上什么高级技巧,它的用法格外的简单,只不过和前面所学的所有属性动画的知识不同,它并不是在3.0系统当中引入的,而是在3.1系统当中附增的一个新的功能,因此这里我们把它作为整个属性动画系列的收尾部分。


    我们都知道,属性动画的机制已经不是再针对于View而进行设计的了,而是一种不断地对值进行操作的机制,它可以将值赋值到指定对象的指定属性上。但是,在绝大多数情况下,我相信大家主要都还是对View进行动画操作的。Android开发团队也是意识到了这一点,没有为View的动画操作提供一种更加便捷的用法确实是有点太不人性化了,于是在Android 3.1系统当中补充了ViewPropertyAnimator这个机制。


    那我们先来回顾一下之前的用法吧,比如我们想要让一个TextView从常规状态变成透明状态,就可以这样写:

    ObjectAnimator animator = ObjectAnimator.ofFloat(textview, "alpha", 0f);
    animator.start();
    看上去复杂吗?好像也不怎么复杂,但确实也不怎么容易理解。我们要将操作的view、属性、变化的值都一起传入到ObjectAnimator.ofFloat()方法当中,虽然看上去也没写几行代码,但这不太像是我们平时使用的面向对象的思维。


    那么下面我们就来看一下如何使用ViewPropertyAnimator来实现同样的效果,ViewPropertyAnimator提供了更加易懂、更加面向对象的API,如下所示:

    textview.animate().alpha(0f);

    果然非常简单!不过textview.animate()这个方法是怎么回事呢?animate()方法就是在Android 3.1系统上新增的一个方法,这个方法的返回值是一个ViewPropertyAnimator对象,也就是说拿到这个对象之后我们就可以调用它的各种方法来实现动画效果了,这里我们调用了alpha()方法并转入0,表示将当前的textview变成透明状态。


    怎么样?比起使用ObjectAnimator,ViewPropertyAnimator的用法明显更加简单易懂吧。除此之外,ViewPropertyAnimator还可以很轻松地将多个动画组合到一起,比如我们想要让textview运动到500,500这个坐标点上,就可以这样写:

    textview.animate().x(500).y(500);
    可以看出,ViewPropertyAnimator是支持连缀用法的,我们想让textview移动到横坐标500这个位置上时调用了x(500)这个方法,然后让textview移动到纵坐标500这个位置上时调用了y(500)这个方法,将所有想要组合的动画通过这种连缀的方式拼接起来,这样全部动画就都会一起被执行。


    那么怎样去设定动画的运行时长呢?很简单,也是通过连缀的方式设定即可,比如我们想要让动画运行5秒钟,就可以这样写:

    textview.animate().x(500).y(500).setDuration(5000);
    除此之外,本篇文章第一部分所学的Interpolator技术我们也可以应用在ViewPropertyAnimator上面,如下所示:
    textview.animate().x(500).y(500).setDuration(5000)
    		.setInterpolator(new BounceInterpolator());
    用法很简单,同样也是使用连缀的方式。相信大家现在都已经体验出来了,ViewPropertyAnimator其实并没有什么太多的技巧可言,用法基本都是大同小异的,需要用到什么功能就连缀一下,因此更多的用法大家只需要去查阅一下文档,看看还支持哪些功能,有哪些接口可以调用就可以了。


    那么除了用法之外,关于ViewPropertyAnimator有几个细节还是值得大家注意一下的:


    • 整个ViewPropertyAnimator的功能都是建立在View类新增的animate()方法之上的,这个方法会创建并返回一个ViewPropertyAnimator的实例,之后的调用的所有方法,设置的所有属性都是通过这个实例完成的。
    • 大家注意到,在使用ViewPropertyAnimator时,我们自始至终没有调用过start()方法,这是因为新的接口中使用了隐式启动动画的功能,只要我们将动画定义完成之后,动画就会自动启动。并且这个机制对于组合动画也同样有效,只要我们不断地连缀新的方法,那么动画就不会立刻执行,等到所有在ViewPropertyAnimator上设置的方法都执行完毕后,动画就会自动启动。当然如果不想使用这一默认机制的话,我们也可以显式地调用start()方法来启动动画。
    • ViewPropertyAnimator的所有接口都是使用连缀的语法来设计的,每个方法的返回值都是它自身的实例,因此调用完一个方法之后可以直接连缀调用它的另一个方法,这样把所有的功能都串接起来,我们甚至可以仅通过一行代码就完成任意复杂度的动画功能。


    好的,那么到这里为止,整个Android属性动画完全解析的系列就全部结束了,感谢大家有耐心看到最后。


    关注我的技术公众号,每天都有优质技术文章推送。关注我的娱乐公众号,工作、学习累了的时候放松一下自己。

    微信扫一扫下方二维码即可关注:

            

    展开全文
  • PHP continuebreak的用法和区别(个人理解) 基于学习Web安全渗透的需要,接触学习到了PHP这门编程语言。学习过程中,对于PHP循环运算中的continuebreak有了点儿自己的理解,同时也不知道哪里记录下自己的笔记,...
    基于学习Web安全渗透的需要,接触学习到了PHP这门编程语言。学习过程中,对于PHP循环运算中的continue和break有了点儿自己的理解,同时也不知道去哪里记录下自己的笔记,放到自己笔记本中又害怕数据丢失,所以,注册了CSDN帐号,记录下自己的第一次,以后都会来这里记录笔记,分享学习心得,错误的地方欢迎各位大佬指正。
    废话不说了,下面说正事。
    --------------------------------------------------------------------------------------------------------------------------------
    continue:直接跳过当前循环运算剩余部分,继续执行下一次循环运算;
    实例:
    
    <?php
    	for($zero=0;$zero<10;$zero++)
    		if($zero==5)
    			{
    				echo "zero=$zero <br>"."Game is over!<br>";
    				continue;
    			}
    		else
    			{
    				echo "zero=$zero <br>" ."Game continue!<br>";
    			}
    		
    ?>
    
    输出结果如下:
    

    在这里插入图片描述
    个人理解:
    当变量zero=5的条件满足下,触发continue语句执行,zero=5的当前循环语句到此结束,输出zero=5,Game is over!进入zero=6的下一个循环运算。

    break:表示跳出循环,并且整个循环不再继续;
    实例:
    
    <?php
    	for($zero=0;$zero<10;$zero++)
    		if($zero==5)
    			{
    				echo "zero=$zero <br>"."Game is over!<br>";
    				break;
    			}
    		else
    			{
    				echo "zero=$zero <br>" ."Game continue!<br>";
    			}
    		
    ?>
    
    输出结果如下:
    

    在这里插入图片描述
    个人理解:
    当变量zero5的条件满足下,触发break语句执行,输出zero=5,Game is over!同时,整个for循环结束!

    展开全文
  • 操作数据库第一步当然是创建表了,传统创建表方法相信大多数人都知道,那么今天我除了会展示传统建表方法之外,还会讲解LitePal这个框架基本用法,并使用它完成同样建表操作,让大家体会到使用框架...
  • 之前一直傻傻分不清楚callapply,每次用时候都查语法,然鹅,这两个方法在工作中却经常用到。今天整理下,希望自己能搞清楚,今后工作中不在需要查语法。 定义 自己总结出来:就是借用别对象方法,为...
  • C#之ActionFunc的用法

    千次阅读 2019-04-12 15:38:11
    C#之ActionFunc的用法 以前我都是通过定义一个delegate写委托的,但是最近看一些外国人写的源码都是用actionfunc方式写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间学习下这两种方式,...
  • this作用: this表示是当前对象本身。...使用this调用其他构造方法.(还只能多调用少,形同鸡肋)。 调用时候位置必须是当前构造方法中第一句。 this不能用于static方法。他还可以区分局
  • self下划线的用法区别 在最新的xcode中,已经不需要我们自己写 set,get 方法,在我们使用@property声明属性时,系统已经自动帮我们生成set,get方法。 同时我们发现在我们访问我们声明的变量时,会有self. 以...
  • 不过这些天又开始研究起 Titanium ,发现其官方出品MVC框架(Alloy)还是挺不错,刚开始苦于没有好代码学习,文档又少,所以一直没详细研究,后来发现原来官方 CodeStrong 就是一套非常不错学习代码...
  • 第一种情况 假设仅仅控制文件丢失,而其他文件没有丢失(主要是归档REDO),那么恢复时候如果选择从备份中恢复控制...恢复后,控制文件会读数据文件头中与CHECKPOINT SCN对应RBA信息确定从那个序列...
  • const 指针 组合在一起有 4种形式。... 注意事项:只要所指对象是常量,必须要用const放在*左边修饰指针,而不能使用普通指针。 const int i = 3;//定义一个常量 const int j = 4; const in...
  • 一、order by的用法 使用order by,一般是用来,依照查询结果的某一列(或多列)属性,进行排序(升序:ASC;降序:DESC;默认为升序)。 当排序列含空值时: ASC:排序列为空值的元组最后显示。 DESC:排序列为...
  • refout的用法

    2012-01-16 21:00:00
    不仅从语法角度,更要从面向对象【OO】角度理解把握。 一、首先应该真正理解“方法” 方法: 1、语法角度:略 2、OO角度:方法是对现实行为或操作一种模拟 比如:学生上课,考试,面试等...
  • popen函数的用法从代码中获取终端执行命令后显示的信息 从代码中获取终端执行命令后显示的信息 popen (建立管道 I/O) 相关函数 pipe, mkfifo, pclose, fork, system, fopen 头文件 #include <stdio.h> ...
  • java中==equals的用法区别 判断两个字符串是否相等 一开始我是这样写的,用==判断两个字符串是否相等,结果一直不可以 //vCode:数据库中这条记录的原本code值 gCode:前端传的code值 String vCode = vendorDao....
  • C# ActionFunc的用法详解

    千次阅读 2019-01-25 10:24:52
    以前我都是通过定义一个delegate写委托,但是最近看一些外国人写源码都是用actionfunc方式写,当时感觉对这很陌生所以看起源码也觉得陌生,所以我就花费时间学习下这两种方式,然后发现确实代码简洁了...
  • @staticmethod@classmethod的用法

    万次阅读 多人点赞 2018-08-21 17:31:14
    讲解一 一般来说,要使用某个类方法,需要先实例化一个对象再调用方法。...这有利于组织代码,把某些应该属于某个类函数给放到那个类里,同时有利于命名空间整洁。 既然@staticmethod@class...
  • this指向和用法

    2019-04-25 21:19:41
    作为前端开发者说,this是我们最常用到一个东西了,但是this是什么呢,其实它是每个函数 this 是在调用时被绑定,完全取决于函数调用位置(也就是函数调用方法),让我们看一看下面例子吧 function foo()...
  • Python中的异常处理try,except的用法

    万次阅读 多人点赞 2018-08-22 11:02:56
    在各种编程语言进行工作学习过程中,都会有一些错误异常,这些错误则以不同方式展现出来,但是也有一些编程语言错误信息无法直接看到,比如htmlcss,只能通过页面显示最终结果判断是否有错误。...
  • 我平时常用是ReactDeveloperTools,当然你也可以用console.log打印出来,但是console.log在asyncawait方法中打印结果可能与预期不符 state不允许使用类型 在setState中不能改变state
  • 我们将通过一个例子看下它跟现在怎么不同。 线性代码vs非线性代码 大部分软件工程师都习惯用一种线性方式编程,至少这是他们开始职业生涯时就被这样教导。当一个程序使用线性方式编写,这意味着它源...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 2,775
精华内容 1,110
关键字:

来和去的用法