高仿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>

 以上就是所有代碼,只是個例子,因此沒有其餘的功能和代碼。佈局

相關文章
相關標籤/搜索