美文网首页
Android从零开始(第五篇)手把手教撸一个仿饿了么Loadi

Android从零开始(第五篇)手把手教撸一个仿饿了么Loadi

作者: bigname | 来源:发表于2019-01-31 13:56 被阅读0次

    前言

    过年放假前最后一天班,就想着做个简单又有趣的小东西。于是决定来写个自定义的LoadingView作为这个App框架的加载效果吧。

    走过路过点歌Start O(∩_∩)O
    Github项目地址

    这篇文章叫你如何搭建手写LoadingView,看完这篇文章你能学会:

    1. 属性动画使用
    2. 自定义View

    --------------------------------关门,上分割线------------------------------------------------
    先看看效果:


    在这里插入图片描述

    有点像饿了么那种风格。
    最重要的,在看到这个效果之前脑中想到的实现思路:

    1.创建item_loading_view.xml布局,把样式先写出来
    2.自定义View,加载这个自定义布局
    3.自定义View内做动画处理
    

    1.布局:item_loading_view.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="wrap_content"
        android:padding="24dp"
        android:layout_height="148dp">
    
        <ImageView
            android:id="@+id/iv_loading"
            android:layout_width="48dp"
            android:layout_height="48dp"
            android:layout_above="@+id/tv_loading"
            android:src="@drawable/ic_favorites" />
        <TextView
            android:id="@+id/tv_loading"
            android:layout_width="wrap_content"
            android:text="加载中..."
            android:layout_marginTop="12dp"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"
            android:layout_height="wrap_content" />
    
    </RelativeLayout>
    

    2.自定义View

    public class LoadingView extends FrameLayout {
    
        public LoadingView(Context context) {
            this(context,null);
        }
    
        public LoadingView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public LoadingView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            // 加载布局
            LayoutInflater.from(mContext).inflate(R.layout.item_loading_view, this);
        }
    
    

    这个时候在Activity的布局中引用的话,能看到这个loadingView的静态效果了。最后最关键的一步
    3.动画效果实现:
    这里面涉及到两个动画效果,一个是那个爱心上下跳动,以及底下一个阴影缩放
    爱心上下跳动效果:

     private void logic() {
            ValueAnimator animator = ValueAnimator.ofInt(0,mJumpHeightPx,0);
            animator.setDuration(800);
            animator.setRepeatMode(ValueAnimator.RESTART);
            animator.setRepeatCount(ValueAnimator.INFINITE);
            animator.setInterpolator(new AccelerateDecelerateInterpolator());
            animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animation) {
                    int value = (int) animation.getAnimatedValue();
                    mIv.setTranslationY(-value);
                    // 为了画shadow
                    mMovePercent = value / 100f;
                    postInvalidate();
                }
            });
            animator.start();
        }
    

    LoaingView构造函数中调用该方法(详细见githun项目源码)
    实现思路:利用属性动画移动
    关于属性动画作用的原理可以去百度几篇文章,一句话概括就是,属性动画提供的是:使用某种变化规则去得到一个不断变化值,然后自己利用这个值去设置控件的属性以达到动画的效果。

    shadow缩放效果:

    @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            // 阴影宽高的一半   最大不超过16 / 8
            float shadowHalfWidth = Math.max(16f,(mIvRight - mIvLeft) / 2 );
            float shadowHalfHeight = Math.max(8f,(mIvBottom - mIvTop) / 2 );
            // 阴影区域中线位置(决定阴影所在位置) yCenter:垂直中线的纵坐标 xCenter:水平中线的横坐标
            float yCenter = mIvLeft + shadowHalfWidth;
            float xCenter = mIvTop + shadowHalfHeight * 2;
            // 缩放的变化量(决定阴影变化大小)
            float horizontalDiff = Math.max(2,(1f - mMovePercent) * shadowHalfWidth * mShadowFlatX);
            float verticalDiff = Math.max(2,(1f - mMovePercent) * shadowHalfHeight * mShadowFlatY);
            Log.d("bigname", "onDraw: " + yCenter + "-----" + xCenter + "------" + horizontalDiff + "--------" + verticalDiff + "-------" + mMovePercent);
            mShadowRectF.set(
                    yCenter - horizontalDiff,
                    xCenter - verticalDiff,
                    yCenter + horizontalDiff,
                    xCenter + verticalDiff
            );
            canvas.drawOval(mShadowRectF, mShadowPaint);
        }
    

    shadow利用画布去实现:
    首先在使用属性动画的时候将变化的值赋给全局变量mMovePercent;并且变化的时候调用postInvalidate()重绘,这样的话在onDraw()方法中接口和mMovePercent就能知道当前动画进行的进度。依此来控制shadow缩放。

    这个自定义LoadingView效果就已经实现了,接下来会对这个控件做些优化,增加更炫的动画效果,然后做好封装。

    源码在上面的github链接

    敬请期待---

    相关文章

      网友评论

          本文标题:Android从零开始(第五篇)手把手教撸一个仿饿了么Loadi

          本文链接:https://www.haomeiwen.com/subject/oybksqtx.html