• 自定义View-----汽泡效果


    先来看一下这次要实现的最终效果:

    首先来实现效果一,为实现效果二做充足的准备,下面开始:

    新建工程,并定义一个自定义View,然后将其定义在布局文件中,里面是空实现,之后会一步步来填充代码:

    MyRing.java:

    public class MyRing extends View {
    
        public MyRing(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
    }

    activity_main.xml:

    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity" >
    
        <com.example.waveview.MyRing
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            />
    
    </RelativeLayout>

    接下来一步步来实现第一张效果图所示的效果,先重写父类的某些方法:

    public class MyRing extends View {
    
        public MyRing(Context context, AttributeSet attrs) {
            super(context, attrs);
        }
    
        /**
         * 大小的测量按系统的默认规则
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        /**
         * 绘制我们的内容
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
        }
    }

    在点击时需要画一个圆,这是第一步,所以需要监听触摸事件:

    public class MyRing extends View {
    
        /**
         * 圆环圆心的X坐标
         */
        private int cx;
    
        /**
         * 圆环圆心的Y坐标
         */
        private int cy;
        private Paint paint;
        /**
         * 线条的厚度
         */
        private float strokeWidth;
    
        public MyRing(Context context, AttributeSet attrs) {
            super(context, attrs);
            // 初始化paint
            paint = new Paint();
            paint.setAntiAlias(true);
            paint.setColor(Color.RED);
            paint.setStyle(Style.STROKE); // 刻画,画线条
            paint.setStrokeWidth(strokeWidth); // 设置条线的厚度
        }
    
        /**
         * 大小的测量按系统的默认规则
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        /**
         * 绘制我们的内容
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /**
             * 绘制圆环,为了看到效果先将半径写死
             */
            canvas.drawCircle(cx, cy, 100, paint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心
                cx = (int) event.getX();
                cy = (int) event.getY();
                invalidate();
                break;
            }
            return true;
        }
    }

    效果如下:

    默认圆画在(0,0)的位置,有了第一步之后,接下来则要让这个圆进行动态渐变,半径、圆边线的粗度都得动态去改变,具体代码如下:

    public class MyRing extends View {
    
        /**
         * 圆环圆心的X坐标
         */
        private int cx;
    
        /**
         * 圆环圆心的Y坐标
         */
        private int cy;
        private Paint paint;
        /**
         * 线条的厚度
         */
        private float strokeWidth;
        /**
         * 圆环的半径
         */
        private float radius;
        private Handler handler = new Handler() {
            public void handleMessage(android.os.Message msg) {
                flushState();
                // 刷新页面 执行onDraw()方法
                invalidate();
                if (paint.getAlpha() != 0) {
                    handler.sendEmptyMessageDelayed(0, 100);
                }
            };
        };
    
        public MyRing(Context context, AttributeSet attrs) {
            super(context, attrs);
            initView();
        }
    
        private void initView() {
            // 初始化paint
            paint = new Paint();
            paint.setAntiAlias(true); // 抗矩齿
            paint.setColor(Color.RED);
            paint.setStyle(Style.STROKE); // 刻画,画线条
            paint.setStrokeWidth(strokeWidth); // 设置条线的厚度
            paint.setAlpha(255); // 设置透明度 ,0--255 0代表完全透明
    
            //
            this.radius = 0;
            strokeWidth = 0;
        }
    
        /**
         * 大小的测量按系统的默认规则
         */
        @Override
        protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
            super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        }
    
        /**
         * 绘制我们的内容
         */
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            /**
             * 绘制圆环
             */
            canvas.drawCircle(cx, cy, radius, paint);
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: // 点击,获得圆环的中心
                cx = (int) event.getX();
                cy = (int) event.getY();
                // 初始化画笔
                initView();
                handler.sendEmptyMessage(0);
                break;
            }
            return true;
        }
    
        /*
         * 刷新状态
         */
        private void flushState() {
            this.radius += 10;
            this.strokeWidth = radius / 4;
            paint.setStrokeWidth(strokeWidth);
    
            int nextAlpha = paint.getAlpha() - 20;
            if (nextAlpha <= 20) {
                nextAlpha = 0;
            }
            paint.setAlpha(nextAlpha);
    
        }
    }

    这时就是图一的效果了,有了这个基础,要实现图二的效果也就不难了,下面来试一下:

    由于是多个圆,所以肯定是需要一个集合来存储,另外需要用一个实体来表示一个圆的多个属性,如下:

        /**
         * 定义一个波浪
         * @author leo
         */
        private class Wave {
            //圆心
            int cx;
            int cy;
            
            //画笔
            Paint p;
            //半径
            int r;
        }

    然后在按下或滑动时,则把相应的点给添加到集合中,并且需要点与点之间有一定的距离才行,挨得太近则不添加,具体逻辑如下:

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                
                int x = (int) event.getX();
                int y = (int) event.getY();
                
                addPoint(x,y);
                
                break;
    
            default:
                break;
            }
            
            return true; 
            
        }

    而添加的方法如下:

    /**
         * 添加新的波浪中心点
         * @param x
         * @param y
         */
        private void addPoint(int x, int y) {
            if(wList.size() == 0){
                addPoint2List(x,y);
                /*
                 * 第一次启动动画
                 */
                isRunning = true;
                handler.sendEmptyMessage(0);
            }else{
                Wave w = wList.get(wList.size()-1);
                
                if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){
                    addPoint2List(x,y);
                }
                
            };
            
        }
    
        /**
         * 添加新的波浪
         * @param x
         * @param y
         */
        private void addPoint2List(int x, int y) {
            Wave w = new Wave();
            w.cx = x;
            w.cy=y;
            Paint pa=new Paint();
            pa.setColor(colors[(int)(Math.random()*4)]);
            pa.setAntiAlias(true);
            pa.setStyle(Style.STROKE);
    
            w.p = pa;
            
            wList.add(w);
        }

    其中当一第一次添加时,则会开启handler去跑圆环动画,其它的则相继往集合中添加,而handler的写法跟一个圆环的写法差不多,这里就不多解释,直接把整个代码贴上来,都比较好理解:

    /**
     * 水波纹效果
     *
     */
    public class MyRingWave extends View{
    
        /**
         * 二个相临波浪中心点的最小距离
         */
        private static final int DIS_SOLP = 13;
    
        protected boolean isRunning = false;
    
        private ArrayList<Wave> wList;
    
        public MyRingWave(Context context, AttributeSet attrs) {
            super(context, attrs);
            wList = new ArrayList<MyRingWave.Wave>();
        }
        
        private Handler handler = new Handler(){
            public void handleMessage(android.os.Message msg) {
    
                //刷新数据
                flushData();
                //刷新页面
                invalidate();
                //循环动画
                if (isRunning) {
                    handler.sendEmptyMessageDelayed(0, 50);
                }
    
            };
        };
        
        @Override
        protected void onDraw(Canvas canvas) {
            for (int i = 0; i < wList.size(); i++) {
                Wave wave = wList.get(i);
                canvas.drawCircle(wave.cx, wave.cy, wave.r, wave.p);
            }
        }
        
        @Override
        public boolean onTouchEvent(MotionEvent event) {
            super.onTouchEvent(event);
            
            switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                
                int x = (int) event.getX();
                int y = (int) event.getY();
                
                addPoint(x,y);
                
                break;
    
            default:
                break;
            }
            
            return true; 
            
        }
        
        /**
         * 添加新的波浪中心点
         * @param x
         * @param y
         */
        private void addPoint(int x, int y) {
            if(wList.size() == 0){
                addPoint2List(x,y);
                /*
                 * 第一次启动动画
                 */
                isRunning = true;
                handler.sendEmptyMessage(0);
            }else{
                Wave w = wList.get(wList.size()-1);
                
                if(Math.abs(w.cx - x)>DIS_SOLP || Math.abs(w.cy-y)>DIS_SOLP){
                    addPoint2List(x,y);
                }
                
            };
            
        }
    
        /**
         * 添加新的波浪
         * @param x
         * @param y
         */
        private void addPoint2List(int x, int y) {
            Wave w = new Wave();
            w.cx = x;
            w.cy=y;
            Paint pa=new Paint();
            pa.setColor(colors[(int)(Math.random()*4)]);
            pa.setAntiAlias(true);
            pa.setStyle(Style.STROKE);
    
            w.p = pa;
            
            wList.add(w);
        }
    
        private int [] colors = new int[]{Color.BLUE,Color.RED,Color.YELLOW,Color.GREEN};
        /**
         * 刷新数据
         */
        private void flushData() {
            
            for (int i = 0; i < wList.size(); i++) {
                
                Wave w = wList.get(i);
                
                //如果透明度为 0 从集合中删除
                int alpha = w.p.getAlpha();
                if(alpha == 0){
                    wList.remove(i);    //删除i 以后,i的值应该再减1 否则会漏掉一个对象,不过,在此处影响不大,效果上看不出来。
                    continue;
                }
                
                alpha-=5;
                if(alpha<5){
                    alpha =0;
                }
                //降低透明度
                w.p.setAlpha(alpha);
                
                //扩大半径
                w.r = w.r+3;
                //设置半径厚度
                w.p.setStrokeWidth(w.r/3);
            }
            
            /*
             * 如果集合被清空,就停止刷新动画
             */
            if(wList.size() == 0){
                isRunning = false;
            }
        }
    
        /**
         * 定义一个波浪
         * @author leo
         */
        private class Wave {
            //圆心
            int cx;
            int cy;
            
            //画笔
            Paint p;
            //半径
            int r;
        }
    }

    对于这个自定义效果倒不是很复杂,但效果还是挺炫滴,以后坚持收集学习好的UI效果。

  • 相关阅读:
    C# 运用StreamReader类和StreamWriter类实现文件的读写操作
    C# 理解FileInfo类的Open()方法
    C# 运用FileInfo类创建、删除文件
    C# 创建子目录
    C# 目录下的文件操作
    C# 运用DirectoryInfo类和FileInfo类
    C# 文件操作概述
    LINUX介绍
    linux iso 下载地址
    ADO.NET梳理
  • 原文地址:https://www.cnblogs.com/webor2006/p/4793516.html
Copyright © 2020-2023  润新知