Material Design - Curved motion
在 5.0 上 提供了很多动画效果方面的 优化 和 设置
在android5.0(api21)及以上,允许自定义这些动画:
1. Touch feedback 触摸反馈
2. Circular Reveal 圆形显示
3. Activity transitions 过渡动画
4. Curved motion 曲线运动
5. View state changes 视图状态变化
4. Curved motion 曲线运动
Material design中的动画依靠曲线,这个曲线适用于时间插值器和控件运动模式。
PathInterpolator类是一个基于贝塞尔曲线(Bézier curve)或路径(Path)对象上的新的插值器。这个插值器指定了一个1x1的方形运动曲线,用(0,0)点和(1,1)定位点还有控制点来作为构造方法中的参数。你还可以定义一个XML资源的路径插值器:
<pathInterpolator xmlns:android="http://schemas.android.com/apk/res/android"android:controlX1="0.4"android:controlY1="0"android:controlX2="1"android:controlY2="1"/>
在materialdesign规范中,系统提供了三个基本的曲线:
@interpolator/fast_out_linear_in.xml
@interpolator/fast_out_slow_in.xml
@interpolator/linear_out_slow_in.xml
你可以传递一个PathInterpolator对象给Animator.setInterpolator()方法。。
ObjectAnimator类有的构造方法,使你能够一次能同时使用两个或多个属性去绘制动画的路径。
例如,下面的动画使用一个Path对象进行视图X和Y属性的动画绘制:
ObjectAnimator mAnimator;
mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path);
…
mAnimator.start();
ObjectAnimator.ofArgbObjectAnimator.ofFloatObjectAnimator.ofIntObjectAnimator.ofMultiFloatObjectAnimator.ofObjectObjectAnimator.ofPropertyValuesHolder
4.2相关代码示例可以参考:
android-sdk-windows\samples\android-21\legacy\ApiDemos\src\com\example\android\apis\animation\PathAnimations.java
PathAnimation.java
/** This application demonstrates the use of Path animation. */
public class PathAnimations extends Activity implements RadioGroup.OnCheckedChangeListener, View.OnLayoutChangeListener { final static Path sTraversalPath = new Path(); final static float TRAVERSE_PATH_SIZE = 7.0f; final static Property<PathAnimations, Point> POINT_PROPERTY = new Property<PathAnimations, Point>(Point.class, "point") { @Override public Point get(PathAnimations object) { View v = object.findViewById(R.id.moved_item); return new Point(Math.round(v.getX()), Math.round(v.getY())); } @Override public void set(PathAnimations object, Point value) { object.setCoordinates(value.x, value.y); } }; static { float inverse_sqrt8 = FloatMath.sqrt(0.125f); RectF bounds = new RectF(1, 1, 3, 3); sTraversalPath.addArc(bounds, 45, 180); sTraversalPath.addArc(bounds, 225, 180); bounds.set(1.5f + inverse_sqrt8, 1.5f + inverse_sqrt8, 2.5f + inverse_sqrt8, 2.5f + inverse_sqrt8); sTraversalPath.addArc(bounds, 45, 180); sTraversalPath.addArc(bounds, 225, 180); bounds.set(4, 1, 6, 3); sTraversalPath.addArc(bounds, 135, -180); sTraversalPath.addArc(bounds, -45, -180); bounds.set(4.5f - inverse_sqrt8, 1.5f + inverse_sqrt8, 5.5f - inverse_sqrt8, 2.5f + inverse_sqrt8); sTraversalPath.addArc(bounds, 135, -180); sTraversalPath.addArc(bounds, -45, -180); sTraversalPath.addCircle(3.5f, 3.5f, 0.5f, Path.Direction.CCW); sTraversalPath.addArc(new RectF(1, 2, 6, 6), 0, 180); } private CanvasView mCanvasView; private ObjectAnimator mAnimator; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.path_animations); mCanvasView = (CanvasView) findViewById(R.id.canvas); mCanvasView.addOnLayoutChangeListener(this); ((RadioGroup) findViewById(R.id.path_animation_type)).setOnCheckedChangeListener(this); } public void setCoordinates(int x, int y) { changeCoordinates((float) x, (float) y); } public void changeCoordinates(float x, float y) { View v = findViewById(R.id.moved_item); v.setX(x); v.setY(y); } public void setPoint(PointF point) { changeCoordinates(point.x, point.y); } @Override public void onCheckedChanged(RadioGroup group, int checkedId) { startAnimator(checkedId); } @Override public void onLayoutChange(View v, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { int checkedId = ((RadioGroup)findViewById(R.id.path_animation_type)).getCheckedRadioButtonId(); if (checkedId != RadioGroup.NO_ID) { startAnimator(checkedId); } } private void startAnimator(int checkedId) { if (mAnimator != null) { mAnimator.cancel(); mAnimator = null; } View view = findViewById(R.id.moved_item); Path path = mCanvasView.getPath(); if (path.isEmpty()) { return; } switch (checkedId) { case R.id.named_components: // Use the named "x" and "y" properties for individual (x, y) // coordinates of the Path and set them on the view object. // The setX(float) and setY(float) methods are called on view. // An int version of this method also exists for animating // int Properties. mAnimator = ObjectAnimator.ofFloat(view, "x", "y", path); break; case R.id.property_components: // Use two Properties for individual (x, y) coordinates of the Path // and set them on the view object. // An int version of this method also exists for animating // int Properties. mAnimator = ObjectAnimator.ofFloat(view, View.X, View.Y, path); break; case R.id.multi_int: // Use a multi-int setter to animate along a Path. The method // setCoordinates(int x, int y) is called on this during the animation. // Either "setCoordinates" or "coordinates" are acceptable parameters // because the "set" can be implied. mAnimator = ObjectAnimator.ofMultiInt(this, "setCoordinates", path); break; case R.id.multi_float: // Use a multi-float setter to animate along a Path. The method // changeCoordinates(float x, float y) is called on this during the animation. mAnimator = ObjectAnimator.ofMultiFloat(this, "changeCoordinates", path); break; case R.id.named_setter: // Use the named "point" property to animate along the Path. // There must be a method setPoint(PointF) on the animated object. // Because setPoint takes a PointF parameter, no TypeConverter is necessary. // In this case, the animated object is PathAnimations. mAnimator = ObjectAnimator.ofObject(this, "point", null, path); break; case R.id.property_setter: // Use the POINT_PROPERTY property to animate along the Path. // POINT_PROPERTY takes a Point, not a PointF, so the TypeConverter // PointFToPointConverter is necessary. mAnimator = ObjectAnimator.ofObject(this, POINT_PROPERTY, new PointFToPointConverter(), path); break; } mAnimator.setDuration(10000); mAnimator.setRepeatMode(Animation.RESTART); mAnimator.setRepeatCount(ValueAnimator.INFINITE); mAnimator.setInterpolator(new LinearInterpolator()); mAnimator.start(); } public static class CanvasView extends FrameLayout { Path mPath = new Path(); Paint mPathPaint = new Paint(); public CanvasView(Context context) { super(context); init(); } public CanvasView(Context context, AttributeSet attrs) { super(context, attrs); init(); } public CanvasView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { setWillNotDraw(false); mPathPaint.setColor(0xFFFF0000); mPathPaint.setStrokeWidth(2.0f); mPathPaint.setStyle(Paint.Style.STROKE); } @Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) { super.onLayout(changed, left, top, right, bottom); if (changed) { Matrix scale = new Matrix(); float scaleWidth = (right-left)/TRAVERSE_PATH_SIZE; float scaleHeight= (bottom-top)/TRAVERSE_PATH_SIZE; scale.setScale(scaleWidth, scaleHeight); sTraversalPath.transform(scale, mPath); } } public Path getPath() { return mPath; } @Override public void draw(Canvas canvas) { canvas.drawPath(mPath, mPathPaint); super.draw(canvas); } } private static class PointFToPointConverter extends TypeConverter<PointF, Point> { Point mPoint = new Point(); public PointFToPointConverter() { super(PointF.class, Point.class); } @Override public Point convert(PointF value) { mPoint.set(Math.round(value.x), Math.round(value.y)); return mPoint; } }
}
path_animations.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <ScrollView android:layout_width="match_parent" android:layout_height="wrap_content"> <RadioGroup android:orientation="horizontal" android:layout_width="wrap_content" android:layout_height="wrap_content" android:id="@+id/path_animation_type" > <RadioButton android:id="@+id/named_components" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Named Components"/> <RadioButton android:id="@+id/property_components" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Property Components"/> <RadioButton android:id="@+id/multi_int" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Multi-int"/> <RadioButton android:id="@+id/multi_float" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Multi-float"/> <RadioButton android:id="@+id/named_setter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Named Property"/> <RadioButton android:id="@+id/property_setter" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Property"/> </RadioGroup> </ScrollView> <view class="com.example.android.apis.animation.PathAnimations$CanvasView" android:id="@+id/canvas" android:layout_width="match_parent" android:layout_height="0px" android:layout_weight="1"> <ImageView android:id="@+id/moved_item" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/frog"/> </view>
</LinearLayout>
Material Design - Curved motion相关推荐
- Android Material Design动画 Curved motion | 曲线运动
Material Design动画 Curved motion | 曲线运动 在materialDesign中,动画是依赖于时间插值器和空间运动模式的.但是在Android5.0或者5.0以后的版本, ...
- ANDROID L——Material Design详解(动画篇)
转载请注明本文出自大苞米的博客(http://blog.csdn.net/a396901990),谢谢支持! Android L: Google已经确认Android L就是Android Lolli ...
- AndroidMaterialDesign动画之Curved Motion
1,Material Design简介 2,MaterialDesign主题Theme 3,android:elevation的使用 4,AndroidMaterialDesign动画之RippleD ...
- Android Material Design动画
最近在看一些关于Material Design的东西,还记得在博客<你所不知道的Activity转场动画--ActivityOptions>中,我们介绍了一种优雅的activity过度动画 ...
- Android(Lollipop/5.0) Material Design(七) 自定义动画
Material Design系列 Android(Lollipop/5.0) Material Design(一) 简介 Android(Lollipop/5.0) Material Design( ...
- android6.0进入Material Design时代
Material Design 官方Material Design详细介绍文档:http://www.google.com/design/spec/material-design/introducti ...
- 【Android】进入Material Design时代
由于本文引用了大量官方文档.图片资源,以及开源社区的Lib和相关图片资源,因此在转载的时候,务必注明来源,如果使用资源请注明资源的出处,尊重版权,尊重别人的劳动成果,谢谢! Material Desi ...
- Flutter OpenContainer 容器转换过渡 Material Design 设计风格的实践
题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,优美的应用体验 来自于细节的处理,更源自于码农的自我要求与努力 Flutter是谷歌推出的最新的移动开发框架. [x1]微信公众号的每日 ...
- Material Design设计规范
作为技术开发者需不需要了解设计规范?个人认为非常需要,一个交流的需要,另一就是了解相关的设计才能储备相应地知识,知道UI开发的方向.这问题非常希望读者能留言讨论. **Android**的设计风格变迁 ...
最新文章
- 心路历程:「双非」研究生数据分析春招
- Shell(4)——测试test、[]、逻辑、||文件-f、-d、-x、-eq、-gt、-ge、-lt、-le、-ne
- .h .dll .lib
- 【CodeForces - 264A】Escape from Stones (模拟,卡精度的处理)
- WinForm 清空界面控件值的小技巧
- JPA + EclipseLink + SAP云平台 = 运行在云端的数据库应用 1
- Java 算法 身份证排序
- require()与 require_once()、 include与include_once()
- 教你如何快速查询快递物流,并自动识别已签收单号
- 极课大数据:培养超级学生,不如打造超级教师
- 评卷系统-答题卡制作参考网站
- python实现whois查询_Python 工具whois查询
- At least one JAR was scanned for TLDs yet contained no TLDs.问题解决方式
- FreeRTOS 任务调度 系统节拍
- html5统计在线人数,html的统计访客人数的代码?
- 一文解决关于建立时间和保持时间的困惑
- 工银亚洲见证开户详细过程和攻略
- Robot framework模拟打开浏览器问题
- 锂电池电量百分比计算_锂电池充放电理论及电量计算方法详解
- 北京可视化暑期学校日志——Day1