Android 定制多边形View和View的拖动与抛掷效果

定制多边形View

继承View类,利用onDraw()方法中的Canvas对象绘制多边形。
其中使用的Paint,代表画笔,可以设置画笔的颜色和着色的方式(填充或者边框)。使用Path设定多边形的路径点。最后用canvas.drawPath(path,paint)方法将多边形在canvas画布上画出来。

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        Paint paint = new Paint();
        paint.setColor(Color.RED);
        paint.setStyle(Paint.Style.FILL_AND_STROKE);
        Path path = new Path(); //使用path绘制多边形
        path.moveTo(0,0);//多边形起点为view的左上顶点
        path.lineTo(getWidth(), 0);//右顶点
        path.lineTo(getWidth() - getWidth()/10, getHeight()/2);
        path.lineTo(getWidth(),getHeight());
        path.lineTo(0,getHeight());//终点
        path.close();//使这些点构成封闭的多边形
        canvas.drawPath(path,paint);
        //边框
        paint.setColor(Color.GREEN);
        paint.setStrokeWidth(4.0f);
        paint.setStyle(Paint.Style.STROKE);
        path.moveTo(0,0);//多边形起点为view的左上顶点
        path.lineTo(getWidth(), 0);//右顶点
        path.lineTo(getWidth() - getWidth()/10, getHeight()/2);
        path.lineTo(getWidth(),getHeight());
        path.lineTo(0,getHeight());//终点
        path.close();//使这些点构成封闭的多边形
        canvas.drawPath(path,paint);
    }

添加View手势处理逻辑

View类中的onTouchEvent方法,对触屏事件的反馈都在此方法中回调。

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        mGD.onTouchEvent(event);
        return true;
    }
    //触摸事件MotionEvent通常有以下几种类型事件需要处理
    ACTION_DOWN  //按下
    ACTION_UP    //抬起
    ACTION_MOVE  //移动
    ACTION_CANCEL//取消

不过由于我们要处理抛掷的效果,所以将event传递给了mGD处理。mGD是Android中的手势探测器GestureDetector,GestureDetector需要传入一个OnGestureListener监听器。在监听器中重写相关手势的逻辑处理,这里我用到了onFling抛掷和onScroll滚动。抛掷和拖动View的效果在这两个方法中完成。

        mGD = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener() {
            private float direction;

            @Override
            public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
                // 有抛掷的情况下,计算抛掷效果
                if (Math.abs(velocityY) > FLING_MIN_VELOCITY) {
                    float offset = velocityY * 0.5f;
                    // 规避fling速度方向相反问题
                    if ((direction > 0 && offset < 0)
                            || (direction < 0 && offset > 0)) {
                        offset = -offset;
                    }

                    if (getY() + offset < 0) {//不要超过顶端
                        offset = -getY();
                    } else if (getY() + getHeight() + offset > screenHeight) {//不要超过底端
                        offset = screenHeight - getY() - getHeight();
                    }

                    offsetTopAndBottom((int) offset);
                }
                return true;
            }

            @Override
            public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
                float offset = e2.getY() - e1.getY(); //offset为movie-down的值,与Y轴方向相反
                if (getY() + offset < 0) {//不要超过顶端
                    offset = -getY();
                } else if (getY() + getHeight() + offset > screenHeight) {//不要超过底端
                    offset = screenHeight - getY() - getHeight();
                }

                direction = offset;
                offsetTopAndBottom((int) offset);
                return true;
            }
        });

View的移动通过offsetTopAndBottom((int) offset)方法在上下偏移给定的值,同样View也有offsetLeftAndRight方法完成左右偏移。

在onScroll中,每一次Move事件都会传入。e1是初始down事件,e2是每次move事件。e2.getY() - e1.getY()即为在Y轴上View每次移动的偏移值,其中再对超出屏幕的情况做以处理,得到即为最终偏移值。

在onFling中,传入的e1和e2几乎为同一个对象,他们Y轴的位置多数情况相同,偶尔偏差也非常小。选取的是velocityY在Y轴抛掷的速度计算偏移值。velocityY会根据手指移动的快慢相应变化。产生onFling回调时也会在回调onFling之前回调onScroll,为了减少对拖动效果的影响,设定Math.abs(velocityY) > FLING_MIN_VELOCITY抛掷速度大于给定的最小值500时,做抛掷处理。由于抛掷velocityY是在很短时间发生,按m/s计算的速度会很大,不适宜用作偏移值,故取了0.5倍offset = velocityY * 0.5f。velocityY经常与手指的抛掷方向相反,所以使用拖动时的方向来矫正。

// 规避fling速度方向相反问题
if ((direction > 0 && offset < 0)
       || (direction < 0 && offset > 0)) {
    offset = -offset;
}

再过滤掉超出屏幕的情况,最终为View需要偏移的位置。

这是最基本的为自定义View增加拖动和抛掷处理逻辑,在每一个步骤都还可以扩散增加一些个性的处理效果。

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值