前些日子在網上看了大神的文章,是模仿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>
以上就是所有代碼,只是個例子,因此沒有其餘的功能和代碼。佈局