源码阅读_属性动画执行过程

源码阅读_属性动画执行过程

在Android开发中有很多地方使用到了属性动画,阅读源码是熟悉API以及相关代码最直接的方式。

在平时开发中使用属性动画最多的就是这类的代码

       val animator = ObjectAnimator.ofFloat(mView, "alpha", 0f, 100f, 50f)
       animator.duration = 1000
       animator.startDelay = 300
       animator.start()

封装数据

代码中第一句ObjectAnimator.ofFloat(…),直接打开源码(ObjectAnimator.java)

public static ObjectAnimator ofFloat(Object target, String propertyName, float... values) {
       ObjectAnimator anim = new ObjectAnimator(target, propertyName);
       anim.setFloatValues(values);
       return anim;
   }

在ofFloat方法中第一行代码是创建一个ObjectAnimator对象,构造函数中传入执行动画的View,以及属性名。

private ObjectAnimator(Object target, String propertyName) {
        setTarget(target);
        setPropertyName(propertyName);
    }

打开构造函数的代码,可以看到函数中又调用两个方法,看意思感觉挺明显一个是设置View,一个是设置属性名。

还是看一下setTarget方法和setPropertyName方法具体执行了什么逻辑

setTarget方法中,

  1. 先获取mTarget,判断获取的mTarget和目标View是否是同一个控件,很明显之前没有设置过mTarget,所以if (oldTarget != target)为true;
  2. 判断动画状态,如果是开始执行动画了就取消;
  3. 将目标View保存到全局变量mTarget中。
private WeakReference<Object> mTarget;

public Object getTarget() {
        return mTarget == null ? null : mTarget.get();
}

@Override
   public void setTarget(@Nullable Object target) {
       final Object oldTarget = getTarget();
       if (oldTarget != target) {
           if (isStarted()) {
               cancel();
           }
           mTarget = target == null ? null : new WeakReference<Object>(target);
           // New target should cause re-initialization prior to starting
           mInitialized = false;
       }
   }

setPropertyName方法中

  1. 判断mValues是否为空;(第一次一定为空, 如果不为空,则用当前值替换数组中的第一个值,以及替换mValuesMap
  2. 保存属性名至全局变量mPropertyName
  3. 设置初始化标识false
    //用于保存属性名的数组
    PropertyValuesHolder[] mValues;
    //用于保存属性名的HashMap
    HashMap<String, PropertyValuesHolder> mValuesMap;

   public void setPropertyName(@NonNull String propertyName) {
        // mValues could be null if this is being constructed piecemeal. Just record the
        // propertyName to be used later when setValues() is called if so.
        if (mValues != null) {
            PropertyValuesHolder valuesHolder = mValues[0];
            String oldName = valuesHolder.getPropertyName();
            valuesHolder.setPropertyName(propertyName);
            mValuesMap.remove(oldName);
            mValuesMap.put(propertyName, valuesHolder);
        }
        mPropertyName = propertyName;
        // New property/values/target should cause re-initialization prior to starting
        mInitialized = false;
    }

这样构造函数执行的内容都搞清楚了,继续看下面设置的代码

        animator.duration = 1000
        animator.startDelay = 300

这部分源码就很简单了,就是保存属性

// ObjectAnimator类中
   @Override
   @NonNull
   public ObjectAnimator setDuration(long duration) {
       super.setDuration(duration);
       return this;
   }

//父类ValueAnimator中
   @Override
   public ValueAnimator setDuration(long duration) {
       if (duration < 0) {
           throw new IllegalArgumentException("Animators cannot have negative duration: " +
                   duration);
       }
       mDuration = duration;
       return this;
   }

注册垂直同步信号

继续下一行代码animator.start()

这个方法里面主要操作一个是取消监听,一个是执行父类的start()方法。


    @Override
    public void start() {
        //AnimationHandler 并不是Android中的Handler,这里可以理解为一个单例工具类
        //取消掉animator之前设置的回调
        AnimationHandler.getInstance().autoCancelBasedOn(this);
        if (DBG) {
            Log.d(LOG_TAG, "Anim target, duration: " + getTarget() + ", " + getDuration());
            for (int i = 0; i < mValues.length; ++i) {
                PropertyValuesHolder pvh = mValues[i];
                Log.d(LOG_TAG, "   Values[" + i + "]: " +
                    pvh.getPropertyName() + ", " + pvh.mKeyframes.getValue(0) + ", " +
                    pvh.mKeyframes.getValue(1));
            }
        }
        super.start();
    }

start()方法中首先后去获取了一个AnimationHandler对象的单例,再调用这个单例的autoCancelBasedOn()方法。
其实AnimationHandler对象并不是Android中的Handler,这里可以理解为一个工具类。
其中的autoCancelBasedOn()方法中执行的内容大致为遍历取消动画下一帧回调监听。(至于哪里注册、使用到这个监听,下面会讲到)


public final static ThreadLocal<AnimationHandler> sAnimatorHandler = new ThreadLocal<>();

public static AnimationHandler getInstance() {
    if (sAnimatorHandler.get() == null) {
        sAnimatorHandler.set(new AnimationHandler());
    }
    return sAnimatorHandler.get();
}   

void autoCancelBasedOn(ObjectAnimator objectAnimator) {
       for (int i = mAnimationCallbacks.size() - 1; i >= 0; i--) {
           AnimationFrameCallback cb = mAnimationCallbacks.get(i);
           if (cb == null) {
               continue;
           }
           if (objectAnimator.shouldAutoCancel(cb)) {
               ((Animator) mAnimationCallbacks.get(i)).cancel();
           }
       }
   }

取消完监听之后调用了父类的start()方法,父类的start()方法中又调用了重载的start(false)方法。

这个重载的start(false)方法就比较重要了,一开始它检查了是否在UI线程执行,又设置动画是否反向播放(从来没有用过反向播放),反向播放的操作逻辑,以及一些状态设置等等。

接下来执行了它比较重要的三个方法addAnimationCallback(0)startAnimation();setCurrentPlayTime(0)

@Override
   public void start() {
       //重载start的方法  参数是是否反
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: Fullpage是一种基于HTML、CSS和JavaScript的网页滚动效果插件,它可以实现网页内容的全屏滚动展示。下面是一个简单的fullpage HTML源代码示例: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>Fullpage Example</title> <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.css"> <style> .section { text-align: center; padding: 50px; color: #fff; } #section1 { background-color: #ff5f45; } #section2 { background-color: #0798ec; } #section3 { background-color: #ffd962; } #section4 { background-color: #4c4a46; } </style> </head> <body> <div id="fullpage"> <div class="section" id="section1"> <h1>第一部分</h1> <p>这是第一部分的内容</p> </div> <div class="section" id="section2"> <h1>第二部分</h1> <p>这是第二部分的内容</p> </div> <div class="section" id="section3"> <h1>第三部分</h1> <p>这是第三部分的内容</p> </div> <div class="section" id="section4"> <h1>第四部分</h1> <p>这是第四部分的内容</p> </div> </div> <script src="https://cdnjs.cloudflare.com/ajax/libs/fullPage.js/3.1.2/fullpage.min.js"></script> <script> new fullpage('#fullpage', { licenseKey: 'YOUR_KEY_HERE', // 在fullPage官网获取许可证密钥 navigation: true, // 显示导航 navigationPosition: 'right', // 导航位置 navigationTooltips: ['Section 1', 'Section 2', 'Section 3', 'Section 4'] // 导航提示 }); </script> </body> </html> 这段代码首先使用<link>标签引入fullpage插件的CSS样式表,然后定义了一些自定义样式和四个section,每个section都有自己的id和背景颜色。在<body>标签内,使用<div>标签创建了一个id为fullpage的容器,包含了四个section的内容。最后,在<script>标签内,使用<script>标签引入fullpage插件的JavaScript文件,并通过new fullpage()方法初始化插件,并设置了一些配置参数,如导航的显示与位置。 通过以上代码,我们可以实现一个基本的fullpage效果,允许用户滚动浏览并导航到不同的网页部分。 ### 回答2: Fullpage是一种用于创建全屏滚动网页效果的HTML源代码。它基于HTML、CSS和JavaScript技术,通过控制滚动事件和页面布局,实现了整个网页的平滑滚动和翻页效果。 Fullpage的HTML源代码主要包括以下几个部分: 1. 基本的HTML结构:包括<html>、<head>和<body>标签,以及一些必要的元素和属性。 2. CSS样式:用于设置全屏滚动页面的样式,包括页面尺寸、背景色、字体、行高等,通过CSS样式可以美化全屏滚动页面的外观。 3. JavaScript控制:通过JavaScript代码来控制全屏滚动效果,包括监听滚动事件、计算滚动距离、切换页面等。这些代码可以通过引入外部的JavaScript文件或内联在HTML中的<script>标签中实现。 4. 分页内容:每个页面的具体内容,可以是文字、图片、音视频等。在Fullpage中,每个分页都是一个独立的section,在HTML中以<div>标签表示,并通过CSS样式来设置其位置和布局。 使用Fullpage的HTML源代码可以创建出一款具有全屏滚动效果的网页,用户可以通过滚动鼠标或触摸屏来浏览不同的页面。它广泛应用于网页设计、产品展示、宣传活动等场景,能够增加网页的交互性和吸引力,提升用户体验。同时,Fullpage的源代码结构清晰,易于理解和修改,具有一定的可扩展性,可以根据具体需求进行自定义设置。 ### 回答3: fullpage html源代码即全屏滚动效果的网页源代码。 在HTML文件中,我们需要引入fullpage的CSS和JS文件,可以通过CDN链接或者下载到本地引入。然后我们创建一个div容器,设置其高度为100%(充满整个屏幕),并指定一个唯一的id,例如"fullpage-container"。 接下来,我们在JavaScript中初始化fullpage插件。首先选择我们之前创建的div容器,使用fullpage()方法进行初始化。在这个方法中,我们可以在配置对象中设置一些参数来自定义全屏滚动效果。 例如,我们可以设置每一页的背景颜色、滚动速度、导航栏样式等。还可以添加回调函数,例如在滚动到某一页时执行一些动画效果或者改变页面内容。 最后,在整个HTML文件中,我们需要在body标签中使用script标签引入我们的JavaScript文件,并在其内部调用我们的fullpage初始化代码。这样,当用户访问我们的网页时,fullpage插件会自动加载并应用全屏滚动效果。 除了fullpage插件之外,我们还可以使用其他类似的全屏滚动效果插件或者自己编写原生的JavaScript代码来实现该效果。但不论使用何种方法,总的来说,我们需要一个用来触发滚动事件的容器,并在滚动过程中对页面内容进行改变。 全屏滚动效果在网页设计中可实现更丰富的交互体验,能够展示更多的内容,并给用户带来更好的浏览体验。通过正确使用fullpage插件或者其他方法,我们可以轻松地实现这一效果。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值