高仿QQ拖拽消息消失效果

前些日子在网上看了大神的文章,是模仿qq的拖拽消息消失的效果,看起来很酷,因此就跟着作了起来,随便记录一下,以便之后复习,有兴趣的朋友也能够看一下。效果图以下:java

可想而知,须要自定义view,另外,还涉及到贝塞尔曲线,用到了一些基础的几何知识,如勾股定理和正弦和余弦等,关于贝塞尔曲线的知识,你们能够上网看详细资料,这里不作赘述,主要是有点烧脑,本人也有点懒O(∩_∩)O哈哈~下面贴代码:android

这个是自定义的view类:canvas

public class TextView extends FrameLayout {
    private PointF mStartPoint, mCurPoint;
    private int mRadius = 20;
    private Paint mPaint;
    private boolean mTouch;
    private boolean isanimationstart = false;
    private Path mPath;
    private android.widget.TextView textView;
    private int banjing;
    private double distance = 0;
    private ImageView imageView;

    public TextView(Context context, AttributeSet attrs) {
        super(context, attrs);
        init();
    }

    public TextView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        init();
    }

    public TextView(Context context) {
        super(context);
        init();
    }

    @Override
    protected void dispatchDraw(Canvas canvas) {
        canvas.saveLayer(new RectF(0, 0, getWidth(), getHeight()), mPaint, Canvas.ALL_SAVE_FLAG);//保存整个屏幕为一个层
        canvas.drawCircle(mStartPoint.x, mStartPoint.y, banjing, mPaint);//在初始化的地方画圆,半径随着拉开的距离而变化
        if (mTouch) {
            calculatePath();//计算贝塞尔曲线路径的定义方法
            canvas.drawCircle(mCurPoint.x, mCurPoint.y, mRadius, mPaint);//在手指点击的地方画圆
            canvas.drawPath(mPath, mPaint);//绘制路径
//            设置textview的位置为手指点击的位置的中心
            textView.setX(mCurPoint.x - textView.getWidth() / 2);
            textView.setY(mCurPoint.y - textView.getHeight() / 2);
        }
        if (!mTouch) {
            if (((int) distance) > 250) {
//                当拉开距离必定后执行消失动画,让textview消失
                imageView.setX(textView.getX() - imageView.getWidth() / 2);
                imageView.setY(textView.getY() - imageView.getHeight() / 2);
                imageView.setVisibility(VISIBLE);
                textView.setVisibility(GONE);
                ((AnimationDrawable) imageView.getDrawable()).start();//执行逐帧动画
                mPath.reset();
                mPaint.reset();//此处进行重置
            } else {//当拉开距离小于250时,让textview还原到初始位置,不消失
                textView.setX(mStartPoint.x - textView.getWidth() / 2);
                textView.setY(mStartPoint.y - textView.getHeight() / 2);
            }
        }
        canvas.restore();//保存状态
        super.dispatchDraw(canvas);//做用是绘制子控件,在上面的话会覆盖掉本身
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                //判断手指触摸点是否在控件的矩形当中
                Rect rects = new Rect();
                int[] location = new int[2];
                textView.getLocationOnScreen(location);//获得控件在屏幕中的坐标
                //赋值给控件的矩形的四边
                rects.left = location[0];
                rects.top = location[1];
                rects.right = textView.getWidth() + rects.left;
                rects.bottom = textView.getHeight() + rects.top;

                if (rects.contains((int) event.getRawX(), (int) event.getRawY())) {
                  //若是点击位置在控件矩形当中,返回true
                    mTouch = true;
                }
            }
            break;
            case MotionEvent.ACTION_UP: {
//               手指拿起还原
                mTouch = false;
            }
            break;
        }
        mCurPoint.set(event.getX(), event.getY());//定位当前手指点击的位置并传给mCurPoint
        postInvalidate();//更新,以后再次调用dispatchdraw方法
        return true;//返回true,以即可以处理下一次的事件
    }

    //    计算出四个切点的坐标并绘制出贝塞尔曲线
    private void calculatePath() {
        float startx = mStartPoint.x;
        float starty = mStartPoint.y;
        float x = mCurPoint.x;
        float y = mCurPoint.y;

        float dx = x - startx;
        float dy = y - starty;
        double a = Math.atan(dy / dx);//a表示夹角α
        //计算出四个点的x,y的偏移量
        float offsetx = (float) (banjing * Math.sin(a));
        float offsety = (float) (banjing * Math.cos(a));

        //分别计算出四个点的坐标
        float x1 = startx + offsetx;
        float y1 = starty - offsety;
        float x2 = x + offsetx;
        float y2 = y - offsety;
        float x4 = startx - offsetx;
        float y4 = starty + offsety;
        float x3 = x - offsetx;
        float y3 = y + offsety;
        //计算控制点的坐标(为两个圆心的中点坐标)
        float controlx = (startx + x) / 2;
        float controly = (starty + y) / 2;
        //路径清空
        mPath.reset();
        mPath.moveTo(x1, y1);//移动点到第一个切点,即贝塞尔曲线的起始点
        mPath.quadTo(controlx, controly, x2, y2);
        mPath.lineTo(x3, y3);
        mPath.quadTo(controlx, controly, x4, y4);
        mPath.lineTo(x1, y1);

        //两个圆心的距离
        distance = Math.sqrt(Math.pow(x - startx, 2) + Math.pow(y - starty, 2));
        banjing = (int) (mRadius - distance / 15);//能够随着拉开距离的变化而变化的半径
        if (banjing < 3) {
            banjing = 0;
            isanimationstart = true;
            if (((int) distance) < 255) {
                isanimationstart = false;
                banjing = 3;
            }
        }
    }


    public void init() {
        mStartPoint = new PointF(200, 250);
        mCurPoint = new PointF();
        mPaint = new Paint();
        mPath = new Path();
        mPaint.setColor(Color.RED);
        mPaint.setStyle(Paint.Style.FILL_AND_STROKE);


        //添加TextView并设置属性
        RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);
        textView = new android.widget.TextView(getContext());
        textView.setText("99+");
        textView.setBackgroundResource(R.drawable.bg);
        textView.setTextSize(22);
        textView.setTextColor(Color.WHITE);
        textView.setLayoutParams(params);
        addView(textView);
        //添加一个imageview以便后面执行消失的逐帧动画并设置参数
        imageView = new ImageView(getContext());
        imageView.setImageResource(R.drawable.tip_anim);
        imageView.setLayoutParams(params);
        imageView.setVisibility(INVISIBLE);
        addView(imageView);
    }
}

 

而后是布局文件XML:(没有多余的,就是把自定义的view设置到布局中)ide

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
    android:background="#3f4050"
    android:orientation="vertical"
    android:paddingBottom="@dimen/activity_vertical_margin"
    android:paddingLeft="@dimen/activity_horizontal_margin"
    android:paddingRight="@dimen/activity_horizontal_margin"
    android:paddingTop="@dimen/activity_vertical_margin"
    android:weightSum="1"
    tools:context="com.heyongrui.qqredpoint.MainActivity">


        <com.heyongrui.qqredpoint.TextView
            android:id="@+id/custom"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_alignParentEnd="true"
            android:layout_alignParentRight="true"
            android:layout_below="@+id/view"></com.heyongrui.qqredpoint.TextView>

</LinearLayout>

 以上就是所有代码,只是个例子,因此没有其余的功能和代码。布局

相关文章
相关标签/搜索