美文网首页
Android最简单的方式实现波浪纹和小球

Android最简单的方式实现波浪纹和小球

作者: AndyWei123 | 来源:发表于2017-08-03 22:56 被阅读0次

    我们先看一下效果

    Wave.gif

    首先说明这里实现的是刚好一个周期的正弦函数,
    我们来说明一下原理,我们是由左向右移动,由于刚好一个周期,所以我们将右边消失的y值正是左边新出现的y值。所以我们可以将函数的y值存储在一个数组里面,然后不断地在数组里面循环地改变不同位置的y值,那么就形成了水波纹效果。

    • 首先我们要两组组数组来存储通过正弦函数的得到的y值,和用来交换时存储的函数。
        private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组
        private float[] mContentTwoys = null;
       private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用
        private float[] mRestoreTwos = null;
    

    然后我们通过x值求出Y的数组

     for (int i = 0; i < mWidth; i++) {
                mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);
                mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);
            }
       private float getYPosition(int x, int swing, int offset, int baseHeight) {
            float cycle = (float) (2 * Math.PI) / mWidth;
            return (float) Math.sin(cycle * x + offset) * swing + baseHeight;
        }
    
    
    • 说明一下这里面的几个值得意思
      x代表x值,swing代表这幅高度,offset代表一开始的sin'的角度,baseHeight代表基础高度大小,mWidth代表控件的宽度。这个在获取控件宽度的时候实现就是Onsizechang的时候。

    • 加下来就是我们移动y值了

      private void changeRestorePosition() {
            if (mWidth != 0) {
                mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示
                System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);
                System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);
    
                mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示
                System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);
                System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);
            }
        }
    

    STEP1 和 STEP2 分别代表不同的移动速度
    而要绘制出图形就必须把y值和底部连成线然后由mWidht多太哦直线形成一个函数

     for (int i = 0; i < mWidth; i++) {
                final int x = i;
                final float y1 = mRestoreOnes[i];
                final float y2 = mRestoreTwos[i];
                canvas.drawLine(x, y2, x, mHeight, mPaint2);
                canvas.drawLine(x, y1, x, mHeight, mPaint1);
            }
    
    • 最后是不断刷新 由于人眼一般能分辨的是30fps 所以 我这里设置是睡眠0.05秒当然你不怕性能影响的话就直接在OnDraw的时候invalidate();
      先面试完整代码
    public class WaveView extends View {
    
        private volatile boolean RUNING=true;
        private final int INIT_BASE_HEIGHT1 = 300;//基础高度
        private final int INIT_BASE_HEIGHT2 = 300;
        private int mHeight;
        private int mWidth;
        private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组
        private float[] mContentTwoys = null;
        private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用
        private float[] mRestoreTwos = null;
        private static final int SWINGONE = 40;//分别代表两个的正弦函数的上下幅度
        private static final int SWINGTWO = 80;
        private static final int OFFSETONE = 0;//代表一开始的sin 的角度 从 0到360
        private static final int OFFSETTWO = 40;
        private int mPosition1 = 0;//代表起始高度
        private int mPosition2 = 0;
        private static final int STEP1 = 5;//这两个分别代表两条线的两个的速率
        private static final int STEP2 = 8;
        private Paint mPaint1;
        private Paint mPaint2;
    
    
        public WaveView(Context context) {
            this(context, null);
        }
    
        public WaveView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint1.setColor(Color.parseColor("#AB9DCF"));
            mPaint1.setStrokeWidth(4);
            mPaint1.setAlpha(125);
    
            mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint2.setColor(Color.parseColor("#A2D1F3"));
            mPaint2.setStrokeWidth(4);
            mPaint2.setAlpha(125);
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            if (w != 0 || h != 0 || w != oldw || h != oldh) {
                mWidth = w;
                mHeight = h;
                calculatePoints();
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.save();
            changeRestorePosition();
            for (int i = 0; i < mWidth; i++) {
                final int x = i;
                final float y1 = mRestoreOnes[i];
                final float y2 = mRestoreTwos[i];
                canvas.drawLine(x, y2, x, mHeight, mPaint2);
                canvas.drawLine(x, y1, x, mHeight, mPaint1);
            }
          //  invalidate();//通过这个来形成循环
        }
    
        private void calculatePoints() {
            mContentOneYs = new float[mWidth];
            mContentTwoys = new float[mWidth];
            mRestoreOnes = new float[mWidth];
            mRestoreTwos = new float[mWidth];
            for (int i = 0; i < mWidth; i++) {
                mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);
                mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);
            }
        }
    
    
        private void changeRestorePosition() {
            if (mWidth != 0) {
                mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示
                System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);
                System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);
    
                mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示
                System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);
                System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);
            }
        }
    
        private float getYPosition(int x, int swing, int offset, int baseHeight) {
            float cycle = (float) (2 * Math.PI) / mWidth;
            return (float) Math.sin(cycle * x + offset) * swing + baseHeight;
        }
    
        public void startAnimotion()
        {
            RUNING=true;
            final Handler handler=new Handler();
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    while (RUNING)
                    {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                invalidate();
                            }
                        });
                    }
                }
            });
            thread.start();
        }
    
        @Override
        protected void onDetachedFromWindow() {
            RUNING=false;
            super.onDetachedFromWindow();
        }
    }
    

    接下来我们要实现小球
    我们只需要设置Paint的模式为DST_OUT,关于Paint的模式请参考
    吴小龙

    image
    代码如下
      mPaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
                mCanvas.drawCircle(mWidth/2,mHeight/2,Math.min(mWidth,mHeight)/2,mPaint2);
                canvas.drawBitmap(bitmap,0,0,null);
    

    然后是居中显示 文字

     Paint textPaint = new Paint();          // 创建画笔
                textPaint.setColor(0xffffffff);        // 设置颜色
                textPaint.setStyle(Paint.Style.FILL);   // 设置样式
                textPaint.setTextSize(120);
                Rect targetRect = new Rect((mWidth-mHeight)/2,  0,mHeight+(mWidth-mHeight)/2, mHeight);
    //            textPaint.measureText("",0,1);
                Paint.FontMetricsInt fontMetrics = mPaint2.getFontMetricsInt();
                int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
                textPaint.setTextAlign(Paint.Align.CENTER);
                canvas.drawText(value+"分", targetRect.centerX(), baseline+50, textPaint);
    

    同时我们在xml里给他设置一个background
    最后得到的效果如下

    GIF3.gif

    最后代码如下

    public class WaveView extends View {
        private int value=80;
        private boolean drawCircle=true;
        private volatile boolean RUNING=true;
        private final int INIT_BASE_HEIGHT1 = 300;//基础高度
        private final int INIT_BASE_HEIGHT2 = 300;
        private int mHeight;
        private int mWidth;
        private float[] mContentOneYs = null;//这两个代表两条线的y值得数据组
        private float[] mContentTwoys = null;
        private float[] mRestoreOnes = null;//这两个分笔试两个数组的备用数组在数组的交换的时候使用
        private float[] mRestoreTwos = null;
        private static final int SWINGONE = 40;//分别代表两个的正弦函数的上下幅度
        private static final int SWINGTWO = 80;
        private static final int OFFSETONE = 0;//代表一开始的sin 的角度 从 0到360
        private static final int OFFSETTWO = 40;
        private int mPosition1 = 0;//代表起始高度
        private int mPosition2 = 0;
        private static final int STEP1 = 5;//这两个分别代表两条线的两个的速率
        private static final int STEP2 = 8;
        private Paint mPaint1;
        private Paint mPaint2;
        private Paint circlePaint;
        Bitmap bitmap;
    
        Canvas mCanvas;
    
        public WaveView(Context context) {
            this(context, null);
        }
    
        public WaveView(Context context, AttributeSet attrs) {
            this(context, attrs, 0);
        }
    
        public WaveView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            init();
        }
    
        private void init() {
            mPaint1 = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint1.setColor(Color.parseColor("#AB9DCF"));
            mPaint1.setStrokeWidth(4);
            mPaint1.setAlpha(125);
    
            mPaint2 = new Paint(Paint.ANTI_ALIAS_FLAG);
            mPaint2.setColor(Color.parseColor("#A2D1F3"));
            mPaint2.setStrokeWidth(4);
            mPaint2.setAlpha(125);
        }
    
    
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    
            bitmap = Bitmap.createBitmap(getMeasuredWidth(),getMeasuredHeight(), Bitmap.Config.ARGB_8888);
            mCanvas = new Canvas(bitmap);
            mCanvas.drawColor(Color.WHITE);
        }
    
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            super.onSizeChanged(w, h, oldw, oldh);
            if (w != 0 || h != 0 || w != oldw || h != oldh) {
                mWidth = w;
                mHeight = h;
                calculatePoints();
            }
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.save();
            init();
            changeRestorePosition();
            for (int i = 0; i < mWidth; i++) {
                final int x = i;
                final float y1 = mRestoreOnes[i];
                final float y2 = mRestoreTwos[i];
                canvas.drawLine(x, y2, x, mHeight, mPaint2);
                canvas.drawLine(x, y1, x, mHeight, mPaint1);
            }
          //  invalidate();//通过这个来形成循环
    
            if(drawCircle)
            {
    
                Paint textPaint = new Paint();          // 创建画笔
                textPaint.setColor(0xffffffff);        // 设置颜色
                textPaint.setStyle(Paint.Style.FILL);   // 设置样式
                textPaint.setTextSize(120);
                Rect targetRect = new Rect((mWidth-mHeight)/2,  0,mHeight+(mWidth-mHeight)/2, mHeight);
    //            textPaint.measureText("",0,1);
                Paint.FontMetricsInt fontMetrics = mPaint2.getFontMetricsInt();
                int baseline = (targetRect.bottom + targetRect.top - fontMetrics.bottom - fontMetrics.top) / 2;
                textPaint.setTextAlign(Paint.Align.CENTER);
                canvas.drawText(value+"分", targetRect.centerX(), baseline+50, textPaint);
            }
            if (drawCircle ) {
                mPaint2.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_OUT));
                mCanvas.drawCircle(mWidth/2,mHeight/2,Math.min(mWidth,mHeight)/2,mPaint2);
                canvas.drawBitmap(bitmap,0,0,null);
            }
        }
    
        private void calculatePoints() {
            mContentOneYs = new float[mWidth];
            mContentTwoys = new float[mWidth];
            mRestoreOnes = new float[mWidth];
            mRestoreTwos = new float[mWidth];
            for (int i = 0; i < mWidth; i++) {
                mContentOneYs[i] = getYPosition(i, SWINGONE, OFFSETONE, INIT_BASE_HEIGHT1);
                mContentTwoys[i] = getYPosition(i, SWINGTWO, OFFSETTWO, INIT_BASE_HEIGHT2);
            }
        }
    
    
        private void changeRestorePosition() {
            if (mWidth != 0) {
                mPosition1 = (mPosition1 + STEP1) % mWidth;//循环显示
                System.arraycopy(mContentOneYs, mPosition1, mRestoreOnes, 0, mWidth - mPosition1);
                System.arraycopy(mContentOneYs, 0, mRestoreOnes, mWidth - mPosition1, mPosition1);
    
                mPosition2 = (mPosition2 + STEP2) % mWidth;//循环显示
                System.arraycopy(mContentTwoys, mPosition2, mRestoreTwos, 0, mWidth - mPosition2);
                System.arraycopy(mContentTwoys, 0, mRestoreTwos, mWidth - mPosition2, mPosition2);
            }
        }
    
        private float getYPosition(int x, int swing, int offset, int baseHeight) {
            float cycle = (float) (2 * Math.PI) / mWidth;
            return (float) Math.sin(cycle * x + offset) * swing + baseHeight;
        }
    
        public void startAnimotion()
        {
            RUNING=true;
            final Handler handler=new Handler();
            Thread thread=new Thread(new Runnable() {
                @Override
                public void run() {
                    while (RUNING)
                    {
                        try {
                            Thread.sleep(50);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        handler.post(new Runnable() {
                            @Override
                            public void run() {
                                invalidate();
                            }
                        });
                    }
                }
            });
            thread.start();
        }
    
        @Override
        protected void onDetachedFromWindow() {
            RUNING=false;
            super.onDetachedFromWindow();
        }
    }
    

    相关文章

      网友评论

          本文标题:Android最简单的方式实现波浪纹和小球

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