模仿QQ拖动清除消息提示

来源:互联网 发布:阳光民间借贷网络借贷 编辑:程序博客网 时间:2024/06/03 18:52

首先感谢这两篇文章提供的思路和代码

http://blog.csdn.net/chenupt/article/details/41478303

http://blog.csdn.net/singwhatiwanna/article/details/42614953

首先看下效果图:


实现原理:

点击屏幕,遍历所有的view,匹配点击的屏幕坐标,是否在某个红点提示的view范围内,是的话,计算红点提示的view,在自定义的布局上对应的坐标位置,计算出来的这个坐标,当做其中的一个圆的圆心,在拖动的过程中,得到的另外的坐标,当做是另外一个圆的圆心,在拖动的过程中,半径变化,但两个圆始终保持半径一样,利用贝塞尔曲线,画出拖动的效果。

重要的代码,都有注释,代码也比较少,代码如下:

/**    * @Title: DragTipsLayout.java  * @Package com.eeb.dragredview  * @Description: TODO(模仿QQ拖动消息提示)  * @author luquan yebo0505@foxmail.com    * @date 2015-1-4 上午11:57:48  * @version V1.0    */package com.eeb.dragtipslayout;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.Rect;import android.graphics.RectF;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import android.view.ViewGroup;import android.widget.LinearLayout;public class DragTipsLayout extends LinearLayout {// 默认定点圆半径public static final float DEFAULT_RADIUS = 10;private int[] mLocationInScreen = new int[2];private Paint paint;private Path path;private boolean dragging;// 手势滑动是的动态坐标float touchX = 0;float touchY = 0;// 锚点坐标,两个圆圆心(手势滑动坐标和要拖动的bageview的中心)的中间点float anchorX = 0;float anchorY = 0;// 定点圆半径float radius = DEFAULT_RADIUS;// 要拖动的View的中心坐标private float mCenterX;private float mCenterY;private View targetView;public DragTipsLayout(Context context) {super(context);init();}public DragTipsLayout(Context context, AttributeSet attrs) {super(context, attrs);init();}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {super.onLayout(changed, l, t, r, b);this.getLocationOnScreen(mLocationInScreen);//DragTisLayout 在屏幕上的位置}@Overrideprotected void dispatchDraw(Canvas canvas) {// TODO Auto-generated method stubsuper.dispatchDraw(canvas);if (dragging) {// 画拖动的效果,这里计算的是在拖动的过程中,半径变化,但两个圆始终保持半径一样,如果半径一大一小不同,需要另外计算float distance = (float) Math.sqrt(Math.pow(touchY - mCenterY, 2)+ Math.pow(touchX - mCenterX, 2));radius = -distance / 20 + DEFAULT_RADIUS;paint.setColor(Color.RED);if (radius > 5) {float offsetX = (float) (radius * Math.sin(Math.atan((touchY - mCenterY) / (touchX - mCenterX))));float offsetY = (float) (radius * Math.cos(Math.atan((touchY - mCenterY) / (touchX - mCenterX))));float x1 = mCenterX - offsetX;float y1 = mCenterY + offsetY;float x2 = touchX - offsetX;float y2 = touchY + offsetY;float x3 = touchX + offsetX;float y3 = touchY - offsetY;float x4 = mCenterX + offsetX;float y4 = mCenterY - offsetY;path.reset();path.moveTo(x1, y1);path.quadTo(anchorX, anchorY, x2, y2);path.lineTo(x3, y3);path.quadTo(anchorX, anchorY, x4, y4);path.lineTo(x1, y1);canvas.drawCircle(mCenterX, mCenterY, radius, paint);canvas.drawPath(path, paint);}if (targetView != null) {//计算字体所占的位置大小,获取拖动的badge大小,以确定在拖动过程中,字体居中,画出拖动的view跟badgeview一样String num = ((BadgeView) targetView).getText().toString();Rect rect = new Rect();paint.getTextBounds(num, 0, num.length(), rect);RectF rectF = new RectF(touchX-targetView.getWidth()/2,touchY-targetView.getHeight()/2,touchX+targetView.getWidth()/2,touchY+targetView.getHeight()/2);canvas.drawOval(rectF, paint);paint.setColor(Color.WHITE);canvas.drawText(num,touchX-rect.centerX(), touchY-rect.centerY(), paint);}}}private void init() {setWillNotDraw(false);path = new Path();paint = new Paint();paint.setAntiAlias(true);paint.setStyle(Paint.Style.FILL_AND_STROKE);paint.setStrokeWidth(1);paint.setColor(Color.RED);}@Overridepublic boolean dispatchTouchEvent(MotionEvent event) {switch (event.getAction()) {case MotionEvent.ACTION_DOWN:findTouchTarget(this, event.getRawX(), event.getRawY());touchX = event.getX();touchY = event.getY();anchorX = touchX;anchorY = touchY;break;case MotionEvent.ACTION_MOVE:touchX = event.getX();touchY = event.getY();anchorX = (mCenterX + touchX) / 2;anchorY = (mCenterY + touchY) / 2;break;case MotionEvent.ACTION_UP:if (radius > 5 && targetView != null)targetView.setVisibility(View.VISIBLE);dragging = false;break;}invalidate();//如果没有拖动, 事件分发不做处理,正常使用点击,长按事件,如果return true,可以理解为事件不传递到子类,各个子view的点击,滑动无效if(dragging)return true;elsereturn super.dispatchTouchEvent(event);}//遍历DragTipsLayout下所有的viewprivate void findTouchTarget(ViewGroup viewGrop, float x, float y) {for (int i = 0; i < viewGrop.getChildCount(); i++) {View temp = viewGrop.getChildAt(i);if (temp instanceof ViewGroup) {ViewGroup tempViewGrop = (ViewGroup) temp;findTouchTarget(tempViewGrop, x, y);//递归查找} else if (temp instanceof BadgeView&&isTouchBadgeView(temp, x, y)){//判断是否是BadgeView并且点击屏幕的坐标在BadgeView的区域范围内dragging = true;}}}private boolean isTouchBadgeView(View view, float x, float y) {int[] location = new int[2];view.getLocationOnScreen(location);int left = location[0];int top = location[1];int right = left + view.getMeasuredWidth();int bottom = top + view.getMeasuredHeight();if (view.getVisibility() == View.VISIBLE && y >= top && y <= bottom&& x >= left && x <= right) {//依据遍历找到的BadgeView,计算对应在DragTipsLayout上的坐标点mCenterX = (left + right) / 2 - - mLocationInScreen[0];mCenterY = (top+bottom)/2 - mLocationInScreen[1];targetView = view;view.setVisibility(View.INVISIBLE);return true;}return false;}}

完整代码下载

欢迎转载,但请说明出处http://blog.csdn.net/yebo0505/article/details/42779441


0 0
原创粉丝点击