博客
关于我
Material Design 系列 Transition
阅读量:515 次
发布时间:2019-03-07

本文共 8191 字,大约阅读时间需要 27 分钟。

该篇涉及内容比较多就不多于废话了,直接x入主题

PathMotion

抽象类PathMotion一个与路径移动相关的,这个基类可以扩展提供运动沿着路径转换,比如指定两个位置进行移动,通过PathMotion路径下指定维度进行移动。该类提供了一个getPath方法,源码如下

public abstract class PathMotion {       public PathMotion() {}    public PathMotion(Context context, AttributeSet attrs) {}    /**     * Provide a Path to interpolate between two points (startX, startY) and     * (endX, endY). This allows controlled curved motion along two dimensions.     *     * @param startX The x coordinate of the starting point.     * @param startY The y coordinate of the starting point.     * @param endX   The x coordinate of the ending point.     * @param endY   The y coordinate of the ending point.     * @return A Path along which the points should be interpolated. The returned Path     * must start at point (startX, startY), typically using     * {@link android.graphics.Path#moveTo(float, float)} and end at (endX, endY).     */    public abstract Path getPath(float startX, float startY, float endX, float endY);}

在Transition里面有具体实现,默认的是直线路径

private static final PathMotion STRAIGHT_PATH_MOTION = new PathMotion() {        @Override        public Path getPath(float startX, float startY, float endX, float endY) {            Path path = new Path();            path.moveTo(startX, startY);            path.lineTo(endX, endY);            return path;        }    };

然而这种效果并不是很友好的,它的继承类Arcmotion诞生了,该类提供了自定义属性:minimumVerticalAngle、minimumHorizontalAngle、ArcMotion_maximumAngle水平方向和垂直方向的最小最大维度。以便于我们xml自定义ChangeBounds引用,getPath经过算法处理得到最终的路径。ChangeBounds本质是一个继承自Transition的类,如果引用了我们自定义的ArcMotion就替换了Transtion默认的直线路径移动,ChangeBounds稍后再细说,先来看看我们该怎么在xml引用自定义的ArcMotion


AutoTransition

工具类,当我们执行ChangeBounds相同控件Id位移渐变,而多余的控件要进行fade变化,该类帮助我们进行移动和调整大小视图中一个场景的变化。

public class AutoTransition extends TransitionSet {       /**     * Constructs an AutoTransition object, which is a TransitionSet which     * first fades out disappearing targets, then moves and resizes existing     * targets, and finally fades in appearing targets.     *     */    public AutoTransition() {        init();    }    public AutoTransition(Context context, AttributeSet attrs) {        super(context, attrs);        init();    }    private void init() {        setOrdering(ORDERING_SEQUENTIAL);        addTransition(new Fade(Fade.OUT)).                addTransition(new ChangeBounds()).                addTransition(new Fade(Fade.IN));    }}

这里的Fade是Transition的子类Visibility的子类,自定义属性提供了Fade的mode设置fadingMode,Fade.in Fade.out值来自其父类的transitionVisibilityMode属性对应的mode,从源码里面不难看出这是一个简单的透明度变化的属性动画

private Animator createAnimation(final View view, float startAlpha, final float endAlpha) {        if (startAlpha == endAlpha) {            return null;        }        view.setTransitionAlpha(startAlpha);        final ObjectAnimator anim = ObjectAnimator.ofFloat(view, "transitionAlpha", endAlpha);        if (DBG) {            Log.d(LOG_TAG, "Created animator " + anim);        }        final FadeAnimatorListener listener = new FadeAnimatorListener(view);        anim.addListener(listener);        anim.addPauseListener(listener);        addListener(new TransitionListenerAdapter() {            @Override            public void onTransitionEnd(Transition transition) {                view.setTransitionAlpha(1);            }        });        return anim;    }

Change系列

ChangeBounds这一过渡捕捉目标视图的布局范围场景改变前后的变化。提供属性是否支持大小裁剪,默认不支持,该类通过Property封装了一系列的键值对,供createAnimator调用,类似ChangeBounds的类还有好几个就不一 一细说,下面列出来如果你感兴趣可以查看相关源码(Change系列与Scene配合TransitionManager使用下面Demo介绍):

  • ChangeBounds

  • ChangeClipBounds

  • ChangeImageTransfor

  • ChangeScroll

  • ChangeTransform


官方demo实践

BasicTransition

透过上面这一点源码粗略过一遍,在脑海中有了多多少少的一点印象,下面开始通过一些demo,来帮助我们进一步的了解Transition。官网提供了一个,实现效果如下:

实现原理:首先要有一个根布局rootView,其次是多个场景View,通过TransitionManager.go(Scene)进行场景变换(注意场景的view对应的id要相同才有效果),而Scene的实例获取方式可以通过new和getSceneForLayout方式,下面来简单看看demo核心代码示例:

public class BasicTransitionFragment extends Fragment        implements RadioGroup.OnCheckedChangeListener {       //.........略..............    @Override    public View onCreateView(LayoutInflater inflater, ViewGroup container,                             Bundle savedInstanceState) {        mSceneRoot = (ViewGroup) view.findViewById(R.id.scene_root);        mScene1 = new Scene(mSceneRoot, (ViewGroup) mSceneRoot.findViewById(R.id.container));        mScene2 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene2, getActivity());        mScene3 = Scene.getSceneForLayout(mSceneRoot, R.layout.scene3, getActivity());        mTransitionManagerForScene3 = TransitionInflater.from(getActivity())                .inflateTransitionManager(R.transition.scene3_transition_manager, mSceneRoot);        return view;    }    @Override    public void onCheckedChanged(RadioGroup group, int checkedId) {        switch (checkedId) {            case R.id.select_scene_1: {                TransitionManager.go(mScene1);                    break;            }            case R.id.select_scene_2: {                TransitionManager.go(mScene2);                break;            }            case R.id.select_scene_3: {                mTransitionManagerForScene3.transitionTo(mScene3);                break;            }            case R.id.select_scene_4: {                //缩放动画完成后重新设置控件大小                TransitionManager.beginDelayedTransition(mSceneRoot);                View square = mSceneRoot.findViewById(R.id.transition_square);                ViewGroup.LayoutParams params = square.getLayoutParams();                int newSize = getResources().getDimensionPixelSize(R.dimen.square_size_expanded);                params.width = newSize;                params.height = newSize;                square.setLayoutParams(params);                break;            }        }    }}

场景的转换我们可以通过TransitionManager.go也可以通过上面代码中的TransitionInflater获取TransitionManager实例调用内部定义的其静态方法transitionTo。

ActivitySceneTransitionBasic

这是一个官方提供的一个Activity无缝切换的demo,Activity的切换通过ActivityOptionsCompat向下兼容,调用ActivityOptionsCompat的startActivity方法,Pair形式封装的键要与跳转界面的值一致。官方源码跳转代码如下(这种效果比较适合用于列表跳转详情界面,起点小说的app就是如此实现)

@Override    public void onItemClick(AdapterView
adapterView, View view, int position, long id) { Item item = (Item) adapterView.getItemAtPosition(position); Intent intent = new Intent(this, DetailActivity.class); intent.putExtra(DetailActivity.EXTRA_PARAM_ID, item.getId()); ActivityOptionsCompat activityOptions = ActivityOptionsCompat.makeSceneTransitionAnimation( this, new Pair
(view.findViewById(R.id.imageview_item), DetailActivity.VIEW_NAME_HEADER_IMAGE), new Pair
(view.findViewById(R.id.textview_name), DetailActivity.VIEW_NAME_HEADER_TITLE)); ActivityCompat.startActivity(this, intent, activityOptions.toBundle()); }//...............下面是详情界面,接手传递数据调用transition方法................................ mItem = Item.getItem(getIntent().getIntExtra(EXTRA_PARAM_ID, 0)); mHeaderImageView = (ImageView) findViewById(R.id.imageview_header); mHeaderTitle = (TextView) findViewById(R.id.textview_title); ViewCompat.setTransitionName(mHeaderImageView, VIEW_NAME_HEADER_IMAGE); ViewCompat.setTransitionName(mHeaderTitle, VIEW_NAME_HEADER_TITLE);

当然如果需要变化的View只有一个就没必要用Pair了,直接调用makeSceneTransitionAnimation(Activity activity,View sharedElement, String sharedElementName) {}即可,实现效果图如下:


开源库Interpolator

动画都少不了插值器,Transition配合Interpolator让效果显得更PL了,在这里推荐两个比较不错的动画插值器相关的库,有了它们基本足以满足我们的开发需求

根据现在了解的Transition系列相关的只是,做一个简单的demo测试一下,效果图如下(录制效果不好见谅哈):

Transition相关的开发中,我们有必要明确一下几点区别:Enter、Exit、ReEnter、allow等相关属性含义,这里以下列代码为例做个简短说明

true
true
true
@transition/scene1
@transition/scene1
@transition/scene1
@transition/scene1
@transition/scene1
@transition/scene1

当然这些属性我们可以不仅可以在Style中定义,还可以代码调用通过Window、Slide等进行配置,在动画执行的时候还可以添加监听,在我们结束当前界面有用到Transition相关的动画,最好在动画结束的时候调用finishAfterTransition();而不是finish方法,这样会显得更自然一些。


哎,Transition动画在低版本不能使用,这是一件令人不太开心的事,我满怀激情的来了,你却让我洗个冷水澡,萎了咋办!!!

你可能感兴趣的文章
Mysql 数据库InnoDB存储引擎中主要组件的刷新清理条件:脏页、RedoLog重做日志、Insert Buffer或ChangeBuffer、Undo Log
查看>>
mysql 数据库中 count(*),count(1),count(列名)区别和效率问题
查看>>
mysql 数据库备份及ibdata1的瘦身
查看>>
MySQL 数据库备份种类以及常用备份工具汇总
查看>>
mysql 数据库存储引擎怎么选择?快来看看性能测试吧
查看>>
MySQL 数据库操作指南:学习如何使用 Python 进行增删改查操作
查看>>
MySQL 数据库的高可用性分析
查看>>
MySQL 数据库设计总结
查看>>
Mysql 数据库重置ID排序
查看>>
Mysql 数据类型一日期
查看>>
MySQL 数据类型和属性
查看>>
mysql 敲错命令 想取消怎么办?
查看>>
Mysql 整形列的字节与存储范围
查看>>
mysql 断电数据损坏,无法启动
查看>>
MySQL 日期时间类型的选择
查看>>
Mysql 时间操作(当天,昨天,7天,30天,半年,全年,季度)
查看>>
MySQL 是如何加锁的?
查看>>
MySQL 是怎样运行的 - InnoDB数据页结构
查看>>
mysql 更新子表_mysql 在update中实现子查询的方式
查看>>
MySQL 有什么优点?
查看>>