Android 贝塞尔曲线实践——波浪式运动

一、波浪效果如下

贝塞尔曲线自定义波浪效果的案例很多,同样方法也很简单,大多数和本案例一样使用二次贝塞尔曲线实现,同样还有一种是PathMeasure的方式,这里我们后续补充,先来看贝塞尔曲线的实现方式。

 

二、代码实现

本案例难点:

①波形图的运动,我们需要在 坐标点x负方向绘制一个完整的波形,当波形运动到0点之后自动从恢复原始位置。

②渐变实现,这里使用LinearGradient,主要是渐变方向,当起始横轴为0坐标,纵轴不为0,渐变方向才为纵向。可参考《Android中的LinearGradient》中的讲解。

代码如下:


public class WaveView extends View {

    private TextPaint mPaint;

    private float dx = 0;

    private float mfactory = 5f/4;  //波浪因数,用于决定波长

    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);
        initPaint();
    }

    private void initPaint() {
        // 实例化画笔并打开抗锯齿
        mPaint = new TextPaint(Paint.ANTI_ALIAS_FLAG );
        mPaint.setAntiAlias(true);
        mPaint.setPathEffect(new CornerPathEffect(10)); //设置线条类型
        mPaint.setStrokeWidth(dip2px(1));
        mPaint.setTextSize(dip2px((12)));
        mPaint.setStyle(Paint.Style.STROKE);
    }
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);

        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        int widthMode = MeasureSpec.getMode(widthMeasureSpec);
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int heightMode = MeasureSpec.getMode(heightMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);

        if(widthMode!=MeasureSpec.EXACTLY){
            width = (int) dip2px(300);
        }
        if(heightMode!=MeasureSpec.EXACTLY){
            height = (int) dip2px(100);
        }
        setMeasuredDimension(width,height);

    }

    public float dip2px(int dp){
        return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dp,getResources().getDisplayMetrics());
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if(getWidth()<1 || getHeight()<1) return;

        int saveCount = canvas.save();
        canvas.translate(0,getHeight()/2);
        drawWave(canvas);
        canvas.restoreToCount(saveCount);

    }


    private void drawWave(Canvas canvas){
        float waveLength = getWidth()*mfactory; //波长
        float top = -getHeight()/2f;
        float bottom = getHeight()/2f;

        int N = (int) Math.ceil(getWidth()/waveLength);
        //最大整数,标示view宽度中能容纳的波的数量

        if(N==0) return;
        Path path = new Path();
        for (int i=-1;i<N;i++) {
            buildWavePath(path,i, waveLength, top, bottom);
        }

        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setColor(Color.CYAN);
        canvas.drawPath(path,mPaint);

        float startX = waveLength * (-1) + dx;
        float endX = waveLength  * N + dx;

        path.lineTo(endX,bottom);
        path.lineTo(startX,bottom);
        path.close();
        mPaint.setStyle(Paint.Style.FILL);
        LinearGradient linearGradient = new LinearGradient(0,top,0,bottom,new int[]{Color.BLUE,Color.CYAN},new float[]{0,0.9f}, Shader.TileMode.CLAMP);
        Shader shader = mPaint.getShader();

        mPaint.setShader(linearGradient);
        canvas.drawPath(path,mPaint);
        mPaint.setShader(shader);

    }

    private void buildWavePath(Path path,int ith,float waveLength,float top,float bottom) {

        float offsetLeft = waveLength * ith + dx;
        if(ith==-1) {
            path.moveTo(offsetLeft, 0);
        }
        path.quadTo(offsetLeft+waveLength/4f,top,offsetLeft+waveLength/2f,0);
        path.quadTo(offsetLeft+waveLength*3f/4f,bottom,offsetLeft+waveLength,0);

    }

    public void startAnim(){
        ValueAnimator animator = ValueAnimator.ofFloat(0,getWidth()*mfactory);
        animator.setDuration(2000);
        animator.setRepeatCount(ValueAnimator.INFINITE);
        animator.setInterpolator(new LinearInterpolator());
        animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
            @Override
            public void onAnimationUpdate(ValueAnimator animation) {
                dx = (float) animation.getAnimatedValue();
                postInvalidate();
            }
        });
        animator.start();
    }


}

 

转载于:https://my.oschina.net/ososchina/blog/3026922

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值