Android Api Demos登顶之路(九十一)Graphics-->TouchPaint

/*
 * 这个demon可以和Graphics->FingerPaint一起对比理解,只不过在本例中应用了多点触控,
 * 通过MotionEvent的一系列统方法检测触摸屏的压力和接触区域的大小等信息,以实现绘制出一些
 * 特殊的效果。在本例中我们对原来的demon进行简化,只针对现在最常用的触摸屏手机进行演示。
 */
public class MainActivity extends Activity {
    private boolean isDrawSplat;
    private boolean fading;
    private static final int[] COLORS = new int[] { Color.BLACK, Color.RED,
            Color.YELLOW, Color.GREEN, Color.CYAN, Color.BLUE, Color.MAGENTA, };
    private static final int BACKGROUND_COLOR = Color.WHITE;
    private SampleView mView;

    private static final int MSG_FADE = 1;
    private static final int CLEAR_ID = Menu.FIRST;
    private static final int FADE_ID = Menu.FIRST+1;
    private static final int DRAWSPLAT_ID = Menu.FIRST+2;
    private static final int FADE_DELAY = 100;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        mView=new SampleView(this);
        setContentView(mView);
        mView.requestFocus();

        if(savedInstanceState!=null){
            fading=savedInstanceState.getBoolean("fading",true);
        }else{
            fading=true;
        }
    }

    //创建菜单
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        menu.add(0,CLEAR_ID,0,"Clear");
        menu.add(0,FADE_ID,0,"Fade").setCheckable(true);
        menu.add(0,DRAWSPLAT_ID,0,"Drawsplat");
        return super.onCreateOptionsMenu(menu);
    }

    @Override
    public boolean onPrepareOptionsMenu(Menu menu) {
        menu.findItem(FADE_ID).setChecked(fading);
        return super.onPrepareOptionsMenu(menu);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
        case CLEAR_ID:
            mView.clear();
            return true;
        case FADE_ID:
            fading=!fading;
            if(fading){
                startFading();
            }else{
                stopFading();
            }
            return true;
        case DRAWSPLAT_ID:
            isDrawSplat=true;
            mView.invalidate();
            return true;
        default:
            return super.onOptionsItemSelected(item);
        }
    }

    private Handler mHandler=new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case MSG_FADE:
                mView.fade();
                sheduleFade();
                break;
            default:
                super.handleMessage(msg);
                break;
            }
        };
    };


    private void stopFading() {
        mHandler.removeMessages(MSG_FADE);
    }

    private void startFading() {
        mHandler.removeMessages(MSG_FADE);
        sheduleFade();
    }



    private void sheduleFade() {
        mHandler.sendMessageDelayed(mHandler.obtainMessage(MSG_FADE), FADE_DELAY);
    }

    @Override
    protected void onResume() {
        super.onResume();
        if(fading){
            startFading();
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        stopFading();
    }

    @Override
    protected void onSaveInstanceState(Bundle outState) {
        super.onSaveInstanceState(outState);
        outState.putBoolean("fading", fading);
    }

    private class SampleView extends View {
        private Paint mPaint;
        private Paint mFadePaint;
        private Bitmap mBitmap;
        private Canvas mCanvas;
        private Random mRandom = new Random();

        private static final int SPLAT_VECTORS = 40;
        private static final int FADE_ALPHA = 0x010;
        private static final int MAX_FADE_STEPS = 256 / FADE_ALPHA + 14;
        private int mFadeSteps = MAX_FADE_STEPS;

        public SampleView(Context context) {
            super(context);
            setFocusable(true);
            setFocusableInTouchMode(true);

            mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            int index = (int) (mRandom.nextFloat() * COLORS.length);
            mPaint.setColor(COLORS[index]);

            mFadePaint = new Paint(Paint.ANTI_ALIAS_FLAG);
            mFadePaint.setColor(BACKGROUND_COLOR);
            mFadePaint.setAlpha(FADE_ALPHA);

            //System.out.println("MAX_FADE_STEPS:" + MAX_FADE_STEPS);
        }

        // 清除绘图板中的内容
        public void clear() {
            if (mCanvas != null) {
                mPaint.setColor(BACKGROUND_COLOR);
                // 用背景色刷新画布
                mCanvas.drawPaint(mPaint);
                invalidate();

                mFadeSteps = MAX_FADE_STEPS;
            }
        }

        /*
         * 当选择fade菜单时将实现渐隐效果,通过一次次使用透明度为FADE_ALPHA颜色为背景色的画笔不断刷新
         * 画布,共刷新MAX_FADE_STEPS次来实现逐渐褪色的效果
         */
        public void fade() {
            if (mCanvas != null && mFadeSteps < MAX_FADE_STEPS) {
                mCanvas.drawPaint(mFadePaint);
                invalidate();
                mFadeSteps++;
            }
        }

        // 当屏幕尺寸变化时使画板占满屏幕
        @Override
        protected void onSizeChanged(int w, int h, int oldw, int oldh) {
            int curW = mBitmap != null ? mBitmap.getWidth() : 0;
            int curH = mBitmap != null ? mBitmap.getHeight() : 0;
            if (curW >= w && curH >= h) {
                return;
            }

            if (curW < w)
                curW = w;
            if (curH < h)
                curH = h;

            Bitmap newBitmap = Bitmap.createBitmap(curW, curH,
                    Bitmap.Config.ARGB_8888);
            Canvas newCanvas = new Canvas();
            newCanvas.setBitmap(newBitmap);
            if (mBitmap != null) {
                newCanvas.drawBitmap(mBitmap, 0, 0, null);
            }
            mBitmap = newBitmap;
            mCanvas = newCanvas;
            // 初始化mFadeSteps
            mFadeSteps = MAX_FADE_STEPS;
        }

        @Override
        protected void onDraw(Canvas canvas) {
            if (mBitmap != null) {
                canvas.drawBitmap(mBitmap, 0, 0, null);
            }
        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
            // 返回执行的动作,例如按下触摸屏或者划动
            int action = event.getActionMasked();
            if (action == MotionEvent.ACTION_DOWN
                    || action == MotionEvent.ACTION_MOVE
                    || action == MotionEvent.ACTION_HOVER_MOVE) {
                // 当执行滑动动作时,返回可用的运动位置的数目。因为系统根据手指移动的距离来判定
                // Move动作,该返回值即为即在判定为是一次滑动动作时在手指移动的距离内记录的点的
                // 数量,我们可以遍历这些点并获取到这些点的信息。也可以理解为返回历史触摸区域的大小
                int N = event.getHistorySize();
                // System.out.println("N:"+N);
                // 获取触控点的个数
                int p = event.getPointerCount();
                for (int i = 0; i < N; i++) {
                    for (int j = 0; j < p; j++) {
                        paint(event.getHistoricalX(j, i), event.getHistoricalY(
                                j, i), event.getHistoricalPressure(j, i),
                                event.getHistoricalTouchMajor(j, i),
                                event.getHistoricalTouchMinor(j, i),
                                event.getHistoricalOrientation(j, i),
                                event.getHistoricalAxisValue(
                                        MotionEvent.AXIS_DISTANCE, j, i),
                                event.getHistoricalAxisValue(
                                        MotionEvent.AXIS_TILT, j, i));

                    }
                }

                for (int j = 0; j < p; j++) {
                    paint(// 获取当前触点的坐标
                    event.getX(j), event.getY(j),
                    // 获取当前触点的压力值
                            event.getPressure(j),
                            // 获取接触区域(定义为一个椭圆形)长轴的长度
                            event.getTouchMajor(j),
                            // 接触区域短轴的长度
                            event.getTouchMinor(j),
                            // 以垂直方向为准接触区域按顺时针方向偏向的弧度值
                            event.getOrientation(j),
                            // 获取动作事件的距离
                            event.getAxisValue(MotionEvent.AXIS_DISTANCE, j),
                            // 获取动作事件的倾斜度
                            event.getAxisValue(MotionEvent.AXIS_TILT, j));

                }
            }
            return true;
        }

        private void paint(float x, float y, float pressure, float major,
                float minor, float orientation, float distace, float tilt) {
            if (mBitmap != null) {
                // 如果接触区域的大小不可用,则使用默认大小
                if (major <= 0 || minor <= 0) {
                    major = minor = 16;
                }
            }

            if (isDrawSplat == true) {
                mPaint.setAlpha(64);
                drawSplat(mCanvas, x, y, orientation, distace, tilt, mPaint);
            }else{
                 mPaint.setAlpha(Math.min((int)(pressure * 128), 255));
                 drawOval(mCanvas, x, y, major, minor, orientation, mPaint);
            }

            mFadeSteps=0;
            invalidate();
        }

        private RectF reusableOvalRect=new RectF();
        private void drawOval(Canvas canvas, float x, float y, float major,
                float minor, float orientation, Paint paint) {
            canvas.save(Canvas.MATRIX_SAVE_FLAG);
            canvas.rotate((float) (orientation*180/Math.PI), x, y);
            reusableOvalRect.left=x-minor/2;
            reusableOvalRect.right=x+minor/2;
            reusableOvalRect.top=y-major/2;
            reusableOvalRect.bottom=y+major/2;
            canvas.drawOval(reusableOvalRect, mPaint);
            canvas.restore();
        }

        // 定义具有扩散效果的画笔图案
        private void drawSplat(Canvas canvas, float x, float y,
                float orientation, float distance, float tilt, Paint paint) {
            float z = distance * 2 + 10;

            // Calculate the center of the spray.
            float nx = (float) (Math.sin(orientation) * Math.sin(tilt));
            float ny = (float) (-Math.cos(orientation) * Math.sin(tilt));
            float nz = (float) Math.cos(tilt);
            if (nz < 0.05) {
                return;
            }
            float cd = z / nz;
            float cx = nx * cd;
            float cy = ny * cd;

            for (int i = 0; i < SPLAT_VECTORS; i++) {
                double direction = mRandom.nextDouble() * Math.PI * 2;
                double dispersion = mRandom.nextGaussian() * 0.2;
                double vx = Math.cos(direction) * dispersion;
                double vy = Math.sin(direction) * dispersion;
                double vz = 1;

                // Apply the nozzle tilt angle.
                double temp = vy;
                vy = temp * Math.cos(tilt) - vz * Math.sin(tilt);
                vz = temp * Math.sin(tilt) + vz * Math.cos(tilt);

                // Apply the nozzle orientation angle.
                temp = vx;
                vx = temp * Math.cos(orientation) - vy * Math.sin(orientation);
                vy = temp * Math.sin(orientation) + vy * Math.cos(orientation);

                // Determine where the paint will hit the surface.
                if (vz < 0.05) {
                    continue;
                }
                float pd = (float) (z / vz);
                float px = (float) (vx * pd);
                float py = (float) (vy * pd);

                // Throw some paint at this location, relative to the center of
                // the spray.
                mCanvas.drawCircle(x + px - cx, y + py - cy, 1.0f, paint);
            }

        }

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值