仿华为03-波浪线-手机管家电量界面

15 篇文章 1 订阅

波浪线原理

本来想在 CSDN 中引用一篇波浪线原理文章放这里,两个原因决定还是在文章中写一写
1 找到的文章有的篇幅过长,重点不突出.有些就是讲的不够透彻.
2 如果去掉原理部分,就和先前两篇文章样式不相符了.内容也少了一大块

原理主要涉及两部分
波浪线画法–贝塞尔曲线
波浪线波动起来–屏幕不断显示新的波浪线

贝塞尔曲线就不介绍了,因为大家都会,不了解的可以百度搜索一下.

如何让屏幕不断显示新的波浪线?
最容易想到的就是一定间隔后绘制一条新的线.这样需要计算左侧起点高度和贝塞尔控制点与结束点,比较复杂,暂不考虑.
第二种方法就是画一条线,长度要多画一个屏幕宽(没必要多画1.5个屏幕).线不变,想办法让屏幕显示的部分变化.

第二种方法里如何让屏幕显示的部分变化?

很多文章说是移动屏幕,这种说法是错误的.容易让人产生混乱,要清楚屏幕就是屏幕,是不会动的.
动的是我们操作的画布 Canvas, 画布的移动本质是画布相对于屏幕参考点的改变.所以才会有人说是移动了屏幕.
这里需要理解画布是无限大的,画布与屏幕重叠的部分会显示画布中图像.其他超出屏幕地方我们看不到,但是仍然是可以作图,可以有内容的.

原理示意图:
error
两个屏幕宽波浪图,初始状态:
这里写图片描述

  1. t0 t 0 时 画布初始位置参考点在左上角,我们在左右两侧各画一个波浪.因为右侧与屏幕重叠,所以会显示右侧波浪图
  2. t1 t 1 时,画布向右侧移动一定位置 canvas.translate(dx,0) 注意示意图的垂直方向是为了示意,实际上画布只在 x 轴移动.同样的波浪图(画法不变),因为画布与屏幕的相对位置变了,所以屏幕显示一部分左侧波浪,一部分右侧波浪
  3. t2 t 2 , t3 t 3 情况类似
  4. t4 t 4 时,画布移动了一个屏幕宽度,此时屏幕显示的为左侧波浪图
  5. t5 t 5 时,画布恢复初始位置,屏幕显示右侧波浪图.因为两侧波浪图一样,所以 t4 t 4 , t5 t 5 看起来是一样的.这也是波浪图能连续无顿挫感的关键

原理效果图

这里写图片描述

效果图代码

public class WaveView extends View {

    Paint mPaint;
    Path mPath;
    float mWidth;
    float mHeight;
    float mPercent = 0;

    public WaveView(Context context) {
        this(context, null);
    }

    public WaveView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public WaveView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    private void init() {
        mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        mPaint.setStrokeWidth(4);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.GRAY);
        mPath = new Path();
        postDelayed(new Runnable() {
            @Override
            public void run() {
                startValueAnimation();
            }
        }, 300);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mWidth = getWidth();
        mHeight = getHeight();

        canvas.translate(mWidth * mPercent, 0);

        // 在画布的 x=0 处画一个点,方便理解原理
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL);
        canvas.drawCircle(0,60,10,mPaint);

        //画波浪线
        mPaint.setColor(Color.GRAY);
        mPaint.setStyle(Paint.Style.STROKE);
        mPath.reset();
        mPath.moveTo(-mWidth,60);
        mPath.quadTo(-mWidth*0.75f,120,-mWidth*0.5f,60);
        mPath.quadTo(-mWidth*0.25f,0,0,60);
        mPath.quadTo(mWidth*0.25f,120,mWidth*0.5f,60);
        mPath.quadTo(mWidth*0.75f,0,mWidth,60);

        canvas.drawPath(mPath, mPaint);
    }

    private void startValueAnimation() {
        ValueAnimator animator = ValueAnimator.ofFloat(0, 1);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setDuration(2000);
        // 设置插值器,默认是加速减速插值器,会导致顿挫感
        animator.setInterpolator(new LinearInterpolator());
        animator.start();
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                mPercent = (float) animation.getAnimatedValue();
                invalidate();
            }
        });
    }
}
备注
插值器需要设置为线性插值器,因为默认为加速减速插值器,会导致动画顿挫感
mPath 是全局变量,所以每次需要 reset()
在画布的 x = 0 处画一个圆点,方便观看画布的变化,理解原理

华为界面实现

这里写图片描述

上图是要仿写的华为界面, 我们这里只涉及了波浪图,不包含文字的显示. 接下来要实现三个效果
波浪图闭合
三个波浪
颜色渐变
波浪图闭合

这个实现是最简单的,我们只需要利用 mPath.lineTo() 把路线闭合即可

     mPath.lineTo(mWidth, mHeight);
     mPath.lineTo(-mWidth, mHeight);
     mPath.close();
三个波浪

三个波浪其实就是绘制三遍,区别在于每个波浪的之间起始位置不同. 这里我们只需要改变给画布移动位置即可.原理和 仿华为02 中小球相对位置类似.

通过比例 mPercent (范围 0-1),来调整. 第2个为 mPercent+0.4 第3个位 mPercent+0.8
注意比例必能超过1

 for (int i = 0; i < 3; i++) {
      mPercent = mPercent + 0.4f * i;
      mPercent = mPercent % 1;
      canvas.save();
      canvas.translate(mWidth * mPercent, 0);
      ....
  }
颜色渐变

颜色渐变用到了 Paint 类中设置着色器 Shader 的方法. 这里用到线性渐变

LinearGradient(float x0, float y0, float x1, float y1, int color0, 
int color1, TileMode tile)

参数:
x0 y0 x1 y1:渐变的两个端点的位置
color0 color1 是端点的颜色
tile:端点范围之外的着色规则,类型是 TileMode。TileMode 一共有 3 个值可选: CLAMP, MIRROR 和 REPEAT。模式会控制在端点之外颜色的改变;因为我们设置了整个屏幕范围的渐变,所以选择哪种模式没有区别.

从 (0,0) 点到 (0.mHeight) 点. 设置 Y 轴的颜色渐变

 Shader shader = new LinearGradient(0, 0, 0, mHeight,
                    Color.argb(255, 129, 186, 248),
                    Color.argb(255, 135, 222, 250), Shader.TileMode.CLAMP);
            mPaint.setShader(shader);

备注
为了使得三个波浪不会因为绘制顺序导后面的覆盖前面的视图.还需要设置画笔的透明度.

修改 onDraw() 实现最终效果

结合上面的三方面,我们修改原理代码中的绘制方法.实现最终效果

 @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        mWidth = getWidth();
        mHeight = getHeight();

        int startHeight = 100;
        for (int i = 0; i < 3; i++) {
            mPercent = mPercent + 0.4f * i;
            mPercent = mPercent % 1;
            canvas.save();
            canvas.translate(mWidth * mPercent, 0);

            //画波浪线
            mPath.reset();
            mPath.moveTo(-mWidth, startHeight);
            mPath.quadTo(-mWidth * 0.75f, startHeight + 80, -mWidth * 0.5f, startHeight);
            mPath.quadTo(-mWidth * 0.25f, startHeight-80, 0, startHeight);
            mPath.quadTo(mWidth * 0.25f, startHeight + 80, mWidth * 0.5f, startHeight);
            mPath.quadTo(mWidth * 0.75f, startHeight-80, mWidth, startHeight);

            mPath.lineTo(mWidth, mHeight);
            mPath.lineTo(-mWidth, mHeight);
            mPath.close();

            Shader shader = new LinearGradient(0, 0, 0, mHeight,
                    Color.argb(255, 129, 186, 248),
                    Color.argb(255, 135, 222, 250), Shader.TileMode.CLAMP);
            mPaint.setShader(shader);
            if (i == 0) {
                mPaint.setAlpha(50);
            }
            if (i == 1) {
                mPaint.setAlpha(100);
            }
            if (i == 2) {
                mPaint.setAlpha(150);
            }
            canvas.drawPath(mPath, mPaint);
            canvas.restore();
        }
    }

最终效果: 项目地址
错误
渐变色更清晰
错误

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值