• Android绘图之渐隐动画


    实现了一个有趣的小东西:使用自定义View绘图,一边画线,画出的线条渐渐变淡,直到消失。效果如下图所示:

    用属性动画或者渐变填充(Shader)可以做到一笔一笔的变化,但要想一笔渐变(手指不抬起边画边渐隐),没在Android中找到现成的API可用。所以,自己做了一个。

    基本的想法是这样的:

    • 在View的onTouchEvent中记录触摸点,生成一条一条的线LineElement,放在一个List中。给每个LineElement配置一个Paint实例。
    • 在onDraw中绘制线段。
    • 变换LineElement的Paint实例的Alpha值。
    • 根据Alpha值重组线段列表

    别的不说了,上代码:

    package com.example.disappearinglines;
    
    import android.content.Context;
    import android.graphics.Canvas;
    import android.graphics.Paint;
    import android.graphics.Path;
    import android.graphics.RectF;
    import android.os.Handler;
    import android.os.Message;
    import android.os.SystemClock;
    import android.support.annotation.NonNull;
    import android.util.AttributeSet;
    import android.util.Log;
    import android.view.MotionEvent;
    import android.view.View;
    
    import java.util.ArrayList;
    import java.util.Collection;
    import java.util.Iterator;
    import java.util.List;
    import java.util.ListIterator;
    
    public class DisappearingDoodleView extends View {
        final static String TAG = "DoodleView";
        class LineElement {
            static final public int ALPHA_STEP = 5;
            static final public int SUBPATH_DIMENSION = 8;
            public LineElement(){
                mPaint = new Paint();
                mPaint.setARGB(255, 255, 0, 0);
                mPaint.setAntiAlias(true);
                mPaint.setStrokeWidth(16);
                mPaint.setStrokeCap(Paint.Cap.BUTT);
                mPaint.setStyle(Paint.Style.STROKE);
            }
            public LineElement(Paint paint){
                mPaint = paint;
            }
    
            public void setPaint(Paint paint){
                mPaint = paint;
            }
    
            public void setAlpha(int alpha){
                mPaint.setAlpha(alpha);
            }
    
    
            public float mStartX = -1;
            public float mStartY = -1;
            public float mEndX = -1;
            public float mEndY = -1;
            public Paint mPaint;
        }
    
        private LineElement mCurrentLine = null;
        private List<LineElement> mLines = null;
    
        private long mElapsed = 0;
        private Handler mHandler = new Handler(){
            @Override
            public void handleMessage(Message msg){
                DisappearingDoodleView.this.invalidate();
            }
        };
    
        public DisappearingDoodleView(Context context){
            super(context);
        }
    
        public DisappearingDoodleView(Context context, AttributeSet attrs){
            super(context, attrs);
        }
    
        @Override
        protected void onDraw(Canvas canvas){
            mElapsed = SystemClock.elapsedRealtime();
            if(mLines != null) {
                for (LineElement e : mLines) {
                    if(e.mStartX < 0 || e.mEndY < 0) continue;
                    canvas.drawLine(e.mStartX, e.mStartY, e.mEndX, e.mEndY, e.mPaint);
                }
                compactPaths();
            }
        }
    
        @Override
        public boolean onTouchEvent(MotionEvent event){
            float x = event.getX();
            float y = event.getY();
    
            int action = event.getAction();
            if(action == MotionEvent.ACTION_UP){// end one line after finger release
                mCurrentLine.mEndX = x;
                mCurrentLine.mEndY = y;
                mCurrentLine = null;
                invalidate();
                return true;
            }
    
            if(action == MotionEvent.ACTION_DOWN){
                mCurrentLine = new LineElement();
                addToPaths(mCurrentLine);
    
                mCurrentLine.mStartX = x;
                mCurrentLine.mStartY = y;
                return true;
            }
    
            if(action == MotionEvent.ACTION_MOVE) {
                mCurrentLine.mEndX = x;
                mCurrentLine.mEndY = y;
                mCurrentLine = new LineElement();
                addToPaths(mCurrentLine);
    
                mCurrentLine.mStartX = x;
                mCurrentLine.mStartY = y;
            }
    
    
            if(mHandler.hasMessages(1)){
                mHandler.removeMessages(1);
            }
            Message msg = new Message();
            msg.what = 1;
            mHandler.sendMessageDelayed(msg, 0);
    
            return true;
        }
    
        private void addToPaths(LineElement element){
            if(mLines == null) {
                mLines = new ArrayList<LineElement>() ;
            }
    
            mLines.add(element);
        }
    
        public void compactPaths(){
    
            int size = mLines.size();
            int index = size - 1;
            if(size == 0) return;
            int baseAlpha = 255 - LineElement.ALPHA_STEP;
            int itselfAlpha;
            LineElement line;
            for(; index >=0 ; index--, baseAlpha -= LineElement.ALPHA_STEP){
                line = mLines.get(index);
                itselfAlpha = line.mPaint.getAlpha();
                if(itselfAlpha == 255){
                    if(baseAlpha <= 0){
                        ++index;
                        break;
                    }
                    line.setAlpha(baseAlpha);
                }else{
                    itselfAlpha -= LineElement.ALPHA_STEP;
                    if(itselfAlpha <= 0){
                        ++index;
                        break;
                    }
                    line.setAlpha(itselfAlpha);
                }
            }
    
            if(index >= size){
                // all sub-path should disappear
                mLines = null;
            }
            else if(index >= 0){
                //Log.i(TAG, "compactPaths from " + index + " to " + (size - 1));
                mLines = mLines.subList(index, size);
            }else{
                // no sub-path should disappear
            }
    
            long interval = 40 - SystemClock.elapsedRealtime() + mElapsed;
            if(interval < 0) interval = 0;
            Message msg = new Message();
            msg.what = 1;
            mHandler.sendMessageDelayed(msg, interval);
        }
    }
    

    这个示例还可以添加一些效果,比如让线条一边变淡一边变细。

    目前还有一些问题,线条粗的话,可以明显看到线段与线段之间有缝隙或裂口,哪位想到怎么优化,可以告诉我,非常感谢。^_^。

  • 相关阅读:
    Cocos开发中Visual Studio下libcurl库开发环境设置
    Cocos2d-x数据持久化-修改数据
    Cocos2d-x数据持久化-查询数据
    Cocos2d-x中SQLite数据库管理工具
    Cocos2d-x中创建SQLite数据库
    Visual Studio下SQLite数据库开发环境设置
    spring01
    String类的常用方法
    基本数据类型的包装类和随机数
    枚举类的使用
  • 原文地址:https://www.cnblogs.com/hehehaha/p/6147413.html
Copyright © 2020-2023  润新知