属性动画实战之扁平化自定义Loading
来源:互联网 发布:视频画中画制作软件 编辑:程序博客网 时间:2024/05/30 23:00
最近换了一个项目组,需要从新开发一个APP,美工给推荐了几个Loading效果,都不是很满意,总觉得有违和感,于是自己从网上找了一个还算满意的效果,自己用代码实现了一遍,顺便重温了一下属性动画,100多行代码轻轻松松搞定。
网上原图效果如下:
Loading的载体其实就是一个自定义的dialog,下面总结一下实现过程:
1,首先,要有一个自定义的view,用来实现一个能屏幕适配的圆点。这里只继承view,不继承surfaceview的原因是不需要频繁的重绘我们的圆点,所以也就不存在阻塞UI线程的问题。
/** * 自定义圆点 * @author lizheng * */public class MyPointView extends View{ /** * 点的半径 */ public int pointW = 20; public void setPointW(int pointW) { this.pointW = pointW; } public MyPointView(Context context) { super(context); } @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setAntiAlias(true); paint.setColor(Color.WHITE); //点的圆心在父控件的正中心 canvas.drawCircle(getWidth()/2, getHeight()/2, pointW, paint); super.onDraw(canvas); }}
2,圆点有了,在实现dialog之前,还需为他设定一些参数。这个diaolg应该是没有标题栏,没有背景,同时为了美观,背景的四角应该使用圆角效果。明确了这几点,首先我们来实现他的shape和style。
shape:
<shape xmlns:android="http://schemas.android.com/apk/res/android" > <corners android:radius="20dp" /> <solid android:color="@color/BaseColor"/></shape>
style:
<style name="PointDialogStyle" parent="@android:style/Theme.Dialog"> <item name="android:windowFrame">@null</item> <item name="android:windowIsFloating">true</item> <item name="android:windowIsTranslucent">false</item> <item name="android:windowNoTitle">true</item> <item name="android:windowBackground">@drawable/dialog_bg</item> <item name="android:backgroundDimEnabled">true</item> </style>
在这里,我们为这个dialog设置了圆角,背景透明,无标题,背景色为纯色。
3,下面就可以开始自定义我们的dialog了,首先,为他实现一个layout,使用动态布局和静态布局都是OK的,这个layout应该是一个横向的线性布局,可以依次排列我们的圆点,并且居中显示,如下:
<?xml version="1.0" encoding="utf-8"?><LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:id="@+id/mianView" android:orientation="horizontal" ></LinearLayout>
4,在开始实现自定义dialog之前,我们来规划一下他应该做哪些事
(1),在构造方法中设置style
(2),根据手机屏幕的宽高,动态计算dialog的宽高
(3),动态计算圆点的半径,并为dialog的父控件添加圆点,数量可控
(4),在页面加载完毕后,在回调内为每一个圆点添加属性动画
(5) , 为属性动画添加监听,并实现动画算法
下面给出完整实现代码:
/** * 自定义Loading效果的Dialog * @author lizheng * */public class MyPointDialog extends Dialog { /** * 点的总数 */ public static final int POINT_NUM = 5; /** * 延迟时间 */ public static final int DELAY = 100; private Context context; private LinearLayout mian; private List<MyPointView> views; private int mScreenW; private int mScreenH; private int dialogW; private int dialogH; public MyPointDialog(Context context) { super(context, R.style.PointDialogStyle); this.context = context; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.mypoint_dialog_view); initView(); getPointView(); } private void getPointView() { views = new ArrayList<MyPointView>(); LinearLayout.LayoutParams lay = new LinearLayout.LayoutParams( mScreenW / 14, mScreenW / 14); for (int i = 0; i < POINT_NUM; i++) { MyPointView pointView = new MyPointView(context); pointView.setLayoutParams(lay); pointView.setPointW(mScreenW / 54); views.add(pointView); mian.addView(pointView); } } private void initView() { mian = (LinearLayout) findViewById(R.id.mianView); Display display = getWindow().getWindowManager().getDefaultDisplay(); // 屏幕宽高 mScreenH = display.getHeight(); mScreenW = display.getWidth(); // dialog宽高 dialogW = (int) (mScreenW * 0.23); dialogH = (int) (mScreenH * 0.1); FrameLayout.LayoutParams fl = new FrameLayout.LayoutParams( Utils.dip2px(context, dialogW), Utils.dip2px(context, dialogH)); mian.setLayoutParams(fl); } @Override public void onWindowFocusChanged(boolean hasFocus) { //创建完毕回调 if (hasFocus) { for (int i = 0; i < POINT_NUM; i++) { final MyPointView view = views.get(i); //计算圆点基于父控件的Y轴位置,公式为:dialog高度的一半 - 圆点父控件高度的一半 int height = mian.getHeight() / 2 - mScreenW / 28; ValueAnimator va = ValueAnimator.ofInt(height, height + mScreenH / 30, height - mScreenH / 27, height); va.setDuration(1800);//动画的持续时间 va.setRepeatCount(Integer.MAX_VALUE);//重复播放 va.setStartDelay(DELAY + DELAY * i);//延迟播放 va.setInterpolator(new DecelerateInterpolator()); va.start(); va.addUpdateListener(new AnimatorUpdateListener() { @SuppressLint("NewApi") @Override public void onAnimationUpdate(ValueAnimator animation) { // Y轴方向变化参数 int parseInt = Integer.parseInt(animation .getAnimatedValue().toString()); view.setY(parseInt); // XY轴大小变化参数 float fraction = animation.getAnimatedFraction(); view.setScaleX(fraction < 0.5 ? 1 - fraction : fraction); view.setScaleY(fraction < 0.5 ? 1 - fraction : fraction); } }); } } super.onWindowFocusChanged(hasFocus); }}
简单说一下动画算法的思路,每个圆点做的事其实是一样的,只是每个点比前一个延迟了近0.1秒的时间,通过使用ValueAnimator,设置圆点的起始位置,上下偏移位置,即可实现,最后在ValueAnimator 的监听方法中对我们圆点的Y轴坐标进行赋值即可。
原图中在位移的同时还有一个透明度的变化,这里为了迎合项目我做了一个修改,动态改变其大小,XY轴方向同时从1缩小至0.5,再从0.5放大至1。实现方法很很简单,getAnimatedFraction()参数返回的是一个从0至1的float值,其意义在于监听动画完成进度,通过判断getAnimatedFraction()的值的大小,就可以实现我们需要的大小变化效果,配合位移,个人觉得比原图更出彩。
至此,自定义扁平化的Loading效果已实现完毕,最近天天加班,比较累,有什么不足的地方还请大家提出,一起学习一起进步。
- 属性动画实战之扁平化自定义Loading
- 【Android自定义View实战】之仿百度加载动画,一种优雅的Loading方式
- 【Android实战】使用帧动画实现自定义loading加载布局
- 自定义loading 以及动画loading
- android 自定义loading动画
- [cocos2dx]自定义loading动画
- 【WEB】实战之html与css扁平化风格博客
- 扁平化之管理
- Android自定义扁平化对话框
- Android自定义扁平化对话框
- 实战属性动画与自定义控件相结合波浪
- Android自定义view之属性动画初见
- 属性动画 自定义属性
- Android属性动画实战
- CSS3动画之loading-1
- CSS3动画之loading-2
- CSS3动画之loading-3
- silverlight初始化屏幕,自定义loading动画
- golang表单提交与服务器的交互
- OLAP 支持---ROLLUP和CUBE语句 group by 的增强版本语句!可进行分层分组模式外 (小计与总计)
- actionbar touch坐标测试
- Linux内核RCU(Read Copy Update)锁简析-前传
- vsftpd配置文件详解
- 属性动画实战之扁平化自定义Loading
- Linux下的硬链接和软链接
- Leetcode# 38 Count and Say
- fancy2D 源码解析 0 基本构成
- 机器学习相似度计算方法选择理论依据
- Spring boot 学习笔记 ---分分钟构建一个web程序(一)
- gpio
- linux下mysql安装和安装遇到的问题
- HT for Web列表和3D拓扑组件的拖拽应用