您好,登錄后才能下訂單哦!
怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能?相信很多沒(méi)有經(jīng)驗(yàn)的人對(duì)此束手無(wú)策,為此本文總結(jié)了問(wèn)題出現(xiàn)的原因和解決方法,通過(guò)這篇文章希望你能解決這個(gè)問(wèn)題。
一個(gè)自定義的view 使用方式也很簡(jiǎn)單
<com.weizhenbin.show.widget.VanishView android:layout_width="30dp" android:layout_height="30dp" android:text="5" android:layout_alignParentBottom="true" android:gravity="center" android:textColor="#fff" android:id="@+id/vv" android:layout_marginBottom="35dp" android:layout_marginLeft="80dp" android:background="@drawable/shape_red_bg"/>
然后先看下源碼
** * Created by weizhenbin on 16/6/1. * <p/> * 一個(gè)可以隨意拖動(dòng)的view */ public class VanishView extends TextView { private Context context; /**窗口管理器*/ private WindowManager windowManager; /**用來(lái)存儲(chǔ)鏡像的imageview*/ private ImageView iv; /** 狀態(tài)欄高度*/ private int statusHeight = 0; /**按下的坐標(biāo)x 相對(duì)于view自身*/ private int dx = 0; /**按下的坐標(biāo)y 相對(duì)于view自身*/ private int dy = 0; /**鏡像bitmap*/ private Bitmap tmp; /**按下的坐標(biāo)x 相對(duì)于屏幕*/ private float downX = 0; /**按下的坐標(biāo)y 相對(duì)于屏幕*/ private float downY = 0; /**屬性動(dòng)畫(huà) 用于回彈效果*/ private ValueAnimator animator; /**窗口參數(shù)*/ private WindowManager.LayoutParams mWindowLayoutParams; /**接口對(duì)象*/ private OnListener listener; public VanishView(Context context) { super(context); init(context); } public VanishView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public VanishView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { this.context = context; windowManager = ((Activity) context).getWindowManager(); statusHeight = getStatusHeight(context); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: dx = (int) event.getX(); dy = (int) event.getY(); downX = event.getRawX(); downY = event.getRawY(); addWindow(context, event.getRawX(), event.getRawY()); setVisibility(INVISIBLE); break; case MotionEvent.ACTION_MOVE: mWindowLayoutParams.x = (int) (event.getRawX() - dx); mWindowLayoutParams.y = (int) (event.getRawY() - statusHeight - dy); windowManager.updateViewLayout(iv, mWindowLayoutParams); break; case MotionEvent.ACTION_UP: int distance=distance(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY)); if(distance<400) { scroll(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY)); }else { if(listener!=null){ listener.onDismiss(); } windowManager.removeView(iv); } break; } return true; } /** * 構(gòu)建一個(gè)窗口 用于存放和移動(dòng)鏡像 * */ private void addWindow(Context context, float downX, float dowmY) { mWindowLayoutParams = new WindowManager.LayoutParams(); mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; iv = new ImageView(context); mWindowLayoutParams.format = PixelFormat.RGBA_8888; mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; mWindowLayoutParams.x = (int) (downX - dx); mWindowLayoutParams.y = (int) (dowmY - statusHeight - dy); //獲取view的鏡像bitmap this.setDrawingCacheEnabled(true); tmp = Bitmap.createBitmap(this.getDrawingCache()); //釋放緩存 this.destroyDrawingCache(); iv.setImageBitmap(tmp); windowManager.addView(iv, mWindowLayoutParams); } /** * 使用屬性動(dòng)畫(huà) 實(shí)現(xiàn)緩慢回彈效果 * */ private void scroll(MyPoint start, MyPoint end) { animator = ValueAnimator.ofObject(new MyTypeEvaluator(), start, end); animator.setDuration(200); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { MyPoint point = (MyPoint) animation.getAnimatedValue(); mWindowLayoutParams.x = (int) (point.x - dx); mWindowLayoutParams.y = (int) (point.y - statusHeight - dy); windowManager.updateViewLayout(iv, mWindowLayoutParams); } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); windowManager.removeView(iv); setVisibility(VISIBLE); } }); animator.start(); } /** * 計(jì)算兩點(diǎn)的距離 */ private int distance(MyPoint point1, MyPoint point2) { int distance = 0; if (point1 != null && point2 != null) { float dx = point1.x - point2.x; float dy = point1.y - point2.y; distance = (int) Math.sqrt(dx * dx + dy * dy); } return distance; } /** * 獲取狀態(tài)欄的高度 */ private static int getStatusHeight(Context context) { int statusHeight = 0; Rect localRect = new Rect(); ((Activity) context).getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect); statusHeight = localRect.top; if (0 == statusHeight) { Class<?> localClass; try { localClass = Class.forName("com.android.internal.R$dimen"); Object localObject = localClass.newInstance(); int i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString()); statusHeight = context.getResources().getDimensionPixelSize(i5); } catch (Exception e) { e.printStackTrace(); } } return statusHeight; } class MyPoint { float x; float y; public MyPoint(float x, float y) { this.x = x; this.y = y; } @Override public String toString() { return "MyPoint{" + "x=" + x + ", y=" + y + '}'; } } class MyTypeEvaluator implements TypeEvaluator<MyPoint> { @Override public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) { MyPoint point = startValue; point.x = startValue.x + fraction * (endValue.x - startValue.x); point.y = startValue.y + fraction * (endValue.y - startValue.y); return point; } } /**事件回調(diào)借口*/ public interface OnListener{ void onDismiss(); } public void setListener(OnListener listener) { this.listener = listener; }
實(shí)現(xiàn)這一功能其實(shí)也不難,這個(gè)功能涉及到以下幾個(gè)知識(shí)點(diǎn)
使用WindowManager添加一個(gè)view
使用ValueAnimator屬性動(dòng)畫(huà)實(shí)現(xiàn)回彈效果
getX和getRawX,getY和getRawY的區(qū)別
1.使用WindowManager添加一個(gè)view
/** * 構(gòu)建一個(gè)窗口 用于存放和移動(dòng)鏡像 * */ private void addWindow(Context context, float downX, float dowmY) { mWindowLayoutParams = new WindowManager.LayoutParams(); mWindowLayoutParams.width = WindowManager.LayoutParams.WRAP_CONTENT; mWindowLayoutParams.height = WindowManager.LayoutParams.WRAP_CONTENT; iv = new ImageView(context); mWindowLayoutParams.format = PixelFormat.RGBA_8888; mWindowLayoutParams.gravity = Gravity.TOP | Gravity.LEFT; mWindowLayoutParams.x = (int) (downX - dx); mWindowLayoutParams.y = (int) (dowmY - statusHeight - dy); //獲取view的鏡像bitmap this.setDrawingCacheEnabled(true); tmp = Bitmap.createBitmap(this.getDrawingCache()); //釋放緩存 this.destroyDrawingCache(); iv.setImageBitmap(tmp); windowManager.addView(iv, mWindowLayoutParams); }
這一步是為了投影一個(gè)鏡像來(lái)達(dá)到拖動(dòng)view的一個(gè)假像效果,使用imageview來(lái)顯示。這里為了使投影沒(méi)用偏移需要了解getX getRawX getY getRawY的區(qū)別
getX和getY 是相對(duì)于view自身的,getRawX和getRawY是像對(duì)屏幕的,這里還要扣除掉狀態(tài)欄的高度。
2.移動(dòng)
windowManager.updateViewLayout(iv, mWindowLayoutParams);
3.使用ValueAnimator屬性動(dòng)畫(huà)實(shí)現(xiàn)回彈效果
這里自定義了TypeEvaluator實(shí)現(xiàn)點(diǎn)的位移動(dòng)畫(huà)
class MyTypeEvaluator implements TypeEvaluator<MyPoint> { @Override public MyPoint evaluate(float fraction, MyPoint startValue, MyPoint endValue) { MyPoint point = startValue; point.x = startValue.x + fraction * (endValue.x - startValue.x); point.y = startValue.y + fraction * (endValue.y - startValue.y); return point; } } /** * 使用屬性動(dòng)畫(huà) 實(shí)現(xiàn)緩慢回彈效果 * */ private void scroll(MyPoint start, MyPoint end) { animator = ValueAnimator.ofObject(new MyTypeEvaluator(), start, end); animator.setDuration(200); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { MyPoint point = (MyPoint) animation.getAnimatedValue(); mWindowLayoutParams.x = (int) (point.x - dx); mWindowLayoutParams.y = (int) (point.y - statusHeight - dy); windowManager.updateViewLayout(iv, mWindowLayoutParams); } }); animator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { super.onAnimationEnd(animation); windowManager.removeView(iv); setVisibility(VISIBLE); } }); animator.start(); }
通過(guò)屬性動(dòng)畫(huà)實(shí)現(xiàn)一個(gè)回彈效果
4.觸發(fā)消失的時(shí)機(jī)
/** * 計(jì)算兩點(diǎn)的距離 */ private int distance(MyPoint point1, MyPoint point2) { int distance = 0; if (point1 != null && point2 != null) { float dx = point1.x - point2.x; float dy = point1.y - point2.y; distance = (int) Math.sqrt(dx * dx + dy * dy); } return distance; }
計(jì)算兩點(diǎn)之間的距離來(lái)觸發(fā)一個(gè)回調(diào)事件。
int distance=distance(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY)); if(distance<400) { scroll(new MyPoint(event.getRawX(), event.getRawY()), new MyPoint(downX, downY)); }else { if(listener!=null){ listener.onDismiss(); } windowManager.removeView(iv); }
Android是一種基于Linux內(nèi)核的自由及開(kāi)放源代碼的操作系統(tǒng),主要使用于移動(dòng)設(shè)備,如智能手機(jī)和平板電腦,由美國(guó)Google公司和開(kāi)放手機(jī)聯(lián)盟領(lǐng)導(dǎo)及開(kāi)發(fā)。
看完上述內(nèi)容,你們掌握怎么在Android中實(shí)現(xiàn)QQ消息提示點(diǎn)拖拽功能的方法了嗎?如果還想學(xué)到更多技能或想了解更多相關(guān)內(nèi)容,歡迎關(guān)注億速云行業(yè)資訊頻道,感謝各位的閱讀!
免責(zé)聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權(quán)請(qǐng)聯(lián)系站長(zhǎng)郵箱:is@yisu.com進(jìn)行舉報(bào),并提供相關(guān)證據(jù),一經(jīng)查實(shí),將立刻刪除涉嫌侵權(quán)內(nèi)容。