粘性控件

来源:互联网 发布:达内java就业 编辑:程序博客网 时间:2024/04/28 18:43

1.1.1. -固定值变成变量

固定值变成成员变量

public class StickyView extends View {

    private Paint paint;

    public StickyView(Context context) {
        this(context, null);
    }
    public StickyView(Context context, AttributeSet attrs) {
        this(context, attrs, 0);
    }
    public StickyView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        //初始化画笔
        paint = new Paint(Paint.ANTI_ALIAS_FLAG);//抗锯齿的画笔
        paint.setColor(Color.RED);
    }
    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        //定义固定圆圆心和半径
        PointF stickCenter = new PointF(600, 600);
        float stickRadius = 30f;
        //定义拖拽  圆圆心和半径
        PointF dragCenter = new PointF(400, 600);
        float dragRadius = 60f;
        //画固定圆
        canvas.drawCircle(stickCenter.x, stickCenter.y, stickRadius, paint);
        //画拖拽圆
        canvas.drawCircle(dragCenter.x, dragCenter.y, dragRadius, paint);
        //固定圆的两个附属点
        PointF[] stickPoints = new PointF[]{
                new PointF(600, 570),
                new PointF(600, 630)
        };
        //拖拽圆的两个附属点
        PointF[] dragPoints = new PointF[]{
                new PointF(400, 540),
                new PointF(400, 660)
        };
        //控制点
        PointF contrlPoint = new PointF(500, 600);
        //画连接部分
        Path path = new Path();
        path.moveTo(stickPoints[0].x, stickPoints[0].y);//移动点1,如果不设置,开始点就默认为(0,0)
        //1-->2画曲线
        path.quadTo(contrlPoint.x, contrlPoint.y, dragPoints[0].x, dragPoints[0].y);//参数:控制点坐标,结束点坐标
        //2-->3画直线
        path.lineTo(dragPoints[1].x, dragPoints[1].y);
        //3-->4画曲线
        path.quadTo(contrlPoint.x, contrlPoint.y, stickPoints[1].x, stickPoints[1].y);
        canvas.drawPath(path, paint);
    }
}

 

1.1.2. -计算变量

复制老师提供的一个几何类GeometryUtil

//计算四个附着点
float yOffset = stickCenter.y - dragCenter.y;
float xOffset = stickCenter.x - dragCenter.x;
Double lineK = null;//斜线与两圆心连接直线的斜率
if (xOffset != 0) {
    lineK = Double.valueOf(yOffset / xOffset);
}
PointF[] dragPoints = GeometryUtil.getIntersectionPoints(dragCenter, dragRadius, lineK);
PointF[] stickPoints = GeometryUtil.getIntersectionPoints(stickCenter, stickRadius, lineK);
//画出四个附着点(检测用的)
paint.setColor(Color.BLUE);//用蓝色画
canvas.drawCircle(dragPoints[0].x, dragPoints[0].y, 3f, paint);
canvas.drawCircle(dragPoints[1].x, dragPoints[1].y, 3f, paint);
canvas.drawCircle(stickPoints[0].x, stickPoints[0].y, 3f, paint);
canvas.drawCircle(stickPoints[1].x, stickPoints[1].y, 3f, paint);
paint.setColor(Color.RED);//恢复原来的颜色
//控制点(两个圆心的中点)
PointF contrlPoint = GeometryUtil.getMiddlePoint(stickCenter, dragCenter);

 

 

1.1.3. -根据触摸事件动态绘制

 

-根据两个圆心的距离,动态计算固定圆的半径

 

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x;
    float y;
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            x = event.getRawX();
            y = event.getRawY();
            //更新拖拽圆的圆心
            updateDragCenter(x, y);
            break;
        case MotionEvent.ACTION_MOVE:
            x = event.getRawX();
            y = event.getRawY();
            //更新拖拽圆的圆心
            updateDragCenter(x, y);
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
    return true;//自己消费事件
}

//获取状态栏高度
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

//为了解决手势不同步的问题,需要将画布上移动状态栏的高度
    //状态栏的高度
    statusBarHeight = Utils.getStatusBarHeight(this);
}

/**
 * 更新拖拽圆的圆心
 */
private void updateDragCenter(float x, float y) {
    dragCenter.set(x, y);
    invalidate();
}

 

 

1.1.4. -事件处理

-超出范围断开,松手消失

-超出范围断开,又放回去了,恢复

-没有超出范围,松手,回弹恢复

 

@Override
public boolean onTouchEvent(MotionEvent event) {
    float x;
    float y;
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            isOutofRange = false;
            x = event.getRawX();
            y = event.getRawY();
            if (!isDisappear) {
                //更新拖拽圆的圆心
                updateDragCenter(x, y);
            }
            break;
        case MotionEvent.ACTION_MOVE:
            x = event.getRawX();
            y = event.getRawY();
            //更新拖拽圆的圆心
            updateDragCenter(x, y);
            //超出范围断开
            float dt = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
            if (dt > dtMax) {
                isOutofRange = true;
                invalidate();
            }
            break;
        case MotionEvent.ACTION_UP:
            if (isOutofRange) {     //超出范围
                float dis = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
                if (dis > dtMax) {
                    Log.e(TAG, "超出范围,松手消失");
                    isDisappear = true;
                    invalidate();

                } else if (dis <= dtMax) {
                    Log.e(TAG, "超出范围,又放回去了,松手恢复");
                    //更新固定圆圆心
                    updateDragCenter(stickCenter.x, stickCenter.y);

                }
            } else {     //没有超出范围
                final PointF startP = new PointF(dragCenter.x, dragCenter.y);

                Log.e(TAG, "没有超出范围,松手回弹恢复: ");
                ValueAnimator va = ValueAnimator.ofFloat(1.0f);
                va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                    @Override
                    public void onAnimationUpdate(ValueAnimator animator) {
                        float fraction = animator.getAnimatedFraction();
                        Log.e(TAG, "fraction: " + fraction);
                        //计算开始点startP到结束点stickCenter之间的所有点
                        PointF p = GeometryUtil.getPointByPercent(startP, stickCenter, fraction);
                        updateDragCenter(p.x, p.y);
                    }
                });
                //插补器
                va.setInterpolator(new OvershootInterpolator(5));
                va.setDuration(500);
                va.start();
            }
            break;
    }
    return true;//自己消费事件
}

 

ondraw()里面判断:

没有超出范围才绘制固定圆

没有dispear才绘制拖拽圆

 

1.1.5. -事件监听回调

//监听事件
public interface OnUpdateListener {
    /**
     * 让小圆点消失调用的方法
     */
    void onDisappear(PointF mDragCenter);

    /**
     * 根据是否超出了范围来做对应操作的方法
     */
    void onReset(boolean isOutofRange);
}

public void setmOnUpdateListener(OnUpdateListener mOnUpdateListener) {
    this.mOnUpdateListener = mOnUpdateListener;
}

 

 

调用:

        if (isOutofRange) {     //超出范围
            float dis = GeometryUtil.getDistanceBetween2Points(stickCenter, dragCenter);
            if (dis > dtMax) {
                Log.e(TAG, "超出范围,松手消失");
                isDisappear = true;
                invalidate();
                if (mOnUpdateListener != null) {
                    mOnUpdateListener.onDisappear(dragCenter);
                }
            } else if (dis <= dtMax) {
                Log.e(TAG, "超出范围,又放回去了,松手恢复");
                //更新固定圆圆心
                updateDragCenter(stickCenter.x, stickCenter.y);
                if (mOnUpdateListener != null) {
                    mOnUpdateListener.onReset(true);
                }
            }
        } else {     //没有超出范围
            final PointF startP = new PointF(dragCenter.x, dragCenter.y);

            Log.e(TAG, "没有超出范围,松手回弹恢复: ");
            ValueAnimator va = ValueAnimator.ofFloat(1.0f);
            va.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
                @Override
                public void onAnimationUpdate(ValueAnimator animator) {
                    float fraction = animator.getAnimatedFraction();
                    Log.e(TAG, "fraction: " + fraction);
                    //计算开始点startP到结束点stickCenter之间的所有点
                    PointF p = GeometryUtil.getPointByPercent(startP, stickCenter, fraction);
                    updateDragCenter(p.x, p.y);
                }
            });
            va.addListener(new AnimatorListenerAdapter() {
                @Override
                public void onAnimationEnd(Animator animation) {
                    super.onAnimationEnd(animation);
                    //动画执行完毕了,就调用接口
                    if (mOnUpdateListener != null) {
                        mOnUpdateListener.onReset(false);
                    }
                }
            });
            //插补器
            va.setInterpolator(new OvershootInterpolator(5));
            va.setDuration(500);
            va.start();
        }
        break;
}

0 0
原创粉丝点击