Android自定義View實(shí)現(xiàn)跟隨手指移動(dòng)
對(duì)View的移動(dòng),實(shí)現(xiàn)的方法有好幾種,原理是通過(guò)改變View的位置來(lái)移動(dòng)View,下面來(lái)實(shí)現(xiàn)這樣的效果

- 動(dòng)畫(huà)的方法
通過(guò)改變View的tranlationX和tranlationY的值來(lái)實(shí)現(xiàn)移動(dòng),首先來(lái)寫(xiě)一個(gè)自定義View類(lèi),重寫(xiě)onTouchEvent方法,實(shí)現(xiàn)構(gòu)造方法
public class MyView extends View {
? ? public MyView(Context context) {
? ? ? ? super(context);
? ? }
? ? public MyView(Context context, @Nullable AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? }
? ? public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? }
? ? @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
? ? public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
? ? ? ? super(context, attrs, defStyleAttr, defStyleRes);
? ? }
? ? @Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? return true;//這里我們要消費(fèi)這個(gè)事件,所以返回了true
? ? }
}關(guān)于移動(dòng)的處理邏輯都在onTouchEvent方法中,下面的代碼主要針對(duì)onTouchEvent方法修改,其它代碼不再貼上了
首先要獲取手指點(diǎn)擊移動(dòng)在屏幕上的坐標(biāo),使用
int x = (int)event.getRawX();//獲取x軸上的位置? int y = (int)event.getRawY();//獲取y軸上的位置
處理事件的模板代碼
switch(event.getAction()){
?? ?case MotionEvent.ACTION_DOWN://點(diǎn)擊事件
?? ??? ?break;
?? ?case MotionEvent.ACTION_MOVE://移動(dòng)事件
?? ??? ?break;
?? ?case MotionEvent.ACTION_UP://離開(kāi)事件
?? ??? ?break;
?? ?default:
?? ??? ?break;
}通過(guò)判斷事件的類(lèi)型,將在ACTION_MOVE事件中計(jì)算移動(dòng)前后的差值來(lái)設(shè)置View的translationX和translationY值來(lái)改變View的位置,這里需要記錄上次的位置,所以需要2個(gè)變量,代碼如下
private int mLaxtX;
private int mLaxtY;
? @Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? int x = (int) event.getRawX();
? ? ? ? int y = (int) event.getRawY();
? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? int deltaX = x - mLastX;//計(jì)算x坐標(biāo)上的差值
? ? ? ? ? ? ? ? int deltaY = y - mLastY;//計(jì)算y坐標(biāo)上的差值
? ? ? ? ? ? ? ? float tranX = getTranslationX() + deltaX ;//要平移的x值
? ? ? ? ? ? ? ? float tranY = getTranslationY() + deltaY;//要平移的y值
? ? ? ? ? ? ? ? setTranslationX(tranX);//設(shè)置值
? ? ? ? ? ? ? ? setTranslationY(tranY);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? mLastX = x;//記錄上次的坐標(biāo)
? ? ? ? mLastY = y;
? ? ? ? return true;
? ? }- layout方法
View在繪制的時(shí)候,會(huì)調(diào)用onLayout方法來(lái)設(shè)置顯示的位置,可以通過(guò)這個(gè)方法來(lái)實(shí)現(xiàn)移動(dòng)
//layout方法實(shí)現(xiàn)
switch (event.getAction()) {
? ?case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? //計(jì)算偏移量
? ? ? ? ? ? ? ? int offsetX = x - mLastX;
? ? ? ? ? ? ? ? int offsetY = y - mLastY;
? ? ? ? ? ? ? ? //重新布局
? ? ? ? ? ? ? ? layout(getLeft() + offsetX, getTop() + offsetY,
? ? ? ? ? ? ? ? ? ? ? ? getRight() + offsetX, getBottom() + offsetY);
? ? ? ? ? ? ? ? //也可以使用下面這種方法
// ? ? ? ? ? ? ? ?offsetLeftAndRight(offsetX);
// ? ? ? ? ? ? ? ?offsetTopAndBottom(offsetY);
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? mLastX = x;
? ? ? ? mLastY = y;- LayoutParams
LayoutParams保存了一個(gè)View的布局參數(shù),通過(guò)改變這個(gè)參數(shù),重繪View也可以實(shí)現(xiàn)移動(dòng)
//LayoutParams方法
?switch (event.getAction()) {
? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? int offsetX = x - mLastX;
? ? ? ? ? ? ? ? int offsetY = y - mLastY;
? ? ? ? ? ? ? ? //示例代碼的父View是LinearLayout
? ? ? ? ? ? ? ? LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
? ? ? ? ? ? ? ? layoutParams.leftMargin = getLeft() + offsetX;
? ? ? ? ? ? ? ? layoutParams.topMargin = getTop() + offsetY;
? ? ? ? ? ? ? ? //下面這兩句都可以使用,setLayoutParams也會(huì)調(diào)用requestLayout
? ? ? ? ? ? ? ? // ? ? ? ? ? ? ? ?setLayoutParams(layoutParams);
? ? ? ? ? ? ? ? requestLayout();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? break;
? ? ? ? }這里先介紹這幾種方法
完整代碼如下:
public class MyView extends View {
? ? public MyView(Context context) {
? ? ? ? super(context);
? ? }
? ? public MyView(Context context, @Nullable AttributeSet attrs) {
? ? ? ? super(context, attrs);
? ? }
? ? public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? }
? ? @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
? ? public MyView(Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
? ? ? ? super(context, attrs, defStyleAttr, defStyleRes);
? ? }
? ? private int mLastX;
? ? private int mLastY;
? ? @Override
? ? public boolean onTouchEvent(MotionEvent event) {
? ? ? ? int x = (int) event.getRawX();
? ? ? ? int y = (int) event.getRawY();
? ? ? ? //動(dòng)畫(huà)實(shí)現(xiàn)移動(dòng)代碼
? ? ? ? //--------------------------------------------------
// ? ? ? ?switch (event.getAction()) {
// ? ? ? ? ? ?case MotionEvent.ACTION_DOWN:
//
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?case MotionEvent.ACTION_MOVE:
// ? ? ? ? ? ? ? ?int delaltax = x - mLastX;
// ? ? ? ? ? ? ? ?int delaltaY = y - mLastY;
// ? ? ? ? ? ? ? ?float tranX = getTranslationX() + delaltax;
// ? ? ? ? ? ? ? ?float tranY = getTranslationY() + delaltaY;
// ? ? ? ? ? ? ? ?setTranslationX(tranX);
// ? ? ? ? ? ? ? ?setTranslationY(tranY);
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?case MotionEvent.ACTION_UP:
//
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?default:
// ? ? ? ? ? ? ? ?break;
// ? ? ? ?}
? ? ? ? //-----------------------------------------------
? ? ? ? //layout方法實(shí)現(xiàn)
// ? ? ? ?switch (event.getAction()) {
// ? ? ? ? ? ?case MotionEvent.ACTION_DOWN:
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?case MotionEvent.ACTION_MOVE:
// ? ? ? ? ? ? ? ?//計(jì)算偏移量
// ? ? ? ? ? ? ? ?int offsetX = x - mLastX;
// ? ? ? ? ? ? ? ?int offsetY = y - mLastY;
// ? ? ? ? ? ? ? ?//重新布局
// ? ? ? ? ? ? ? ?layout(getLeft() + offsetX, getTop() + offsetY,
// ? ? ? ? ? ? ? ? ? ? ? ?getRight() + offsetX, getBottom() + offsetY);
// ? ? ? ? ? ? ? ?//也可以使用下面這種方法
? ? ? ? ? ? ? ? offsetLeftAndRight(offsetX);
? ? ? ? ? ? ? ? offsetTopAndBottom(offsetY);
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?case MotionEvent.ACTION_UP:
// ? ? ? ? ? ? ? ?break;
// ? ? ? ? ? ?default:
// ? ? ? ? ? ? ? ?break;
// ? ? ? ?}
? ? ? ? //---------------------------------------------
? ? ? ? //LayoutParams方法
? ? ? ? switch (event.getAction()) {
? ? ? ? ? ? case MotionEvent.ACTION_DOWN:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_MOVE:
? ? ? ? ? ? ? ? int offsetX = x - mLastX;
? ? ? ? ? ? ? ? int offsetY = y - mLastY;
? ? ? ? ? ? ? ? //示例代碼的父View是LinearLayout
? ? ? ? ? ? ? ? LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
? ? ? ? ? ? ? ? layoutParams.leftMargin = getLeft() + offsetX;
? ? ? ? ? ? ? ? layoutParams.topMargin = getTop() + offsetY;
? ? ? ? ? ? ? ? //下面這兩句都可以使用,setLayoutParams也會(huì)調(diào)用requestLayout
? ? ? ? ? ? ? ? // ? ? ? ? ? ? ? ?setLayoutParams(layoutParams);
? ? ? ? ? ? ? ? requestLayout();
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? case MotionEvent.ACTION_UP:
? ? ? ? ? ? ? ? break;
? ? ? ? ? ? default:
? ? ? ? ? ? ? ? break;
? ? ? ? }
? ? ? ? mLastX = x;
? ? ? ? mLastY = y;
? ? ? ? return true;
? ? }
}以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android studio 運(yùn)行main 函數(shù)的方法
這篇文章主要介紹了Android studio 運(yùn)行main 函數(shù)的方法,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09
Android開(kāi)發(fā)中自定義ProgressBar控件的方法示例
這篇文章主要介紹了Android開(kāi)發(fā)中自定義ProgressBar控件的方法,結(jié)合實(shí)例形式分析了自定義ProgressBar控件的定義與使用方法,需要的朋友可以參考下2017-10-10
Android recycleView的應(yīng)用和點(diǎn)擊事件實(shí)例詳解
這篇文章主要介紹了Android recycleView的應(yīng)用和點(diǎn)擊事件實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2016-12-12
Android實(shí)現(xiàn)TextView字符串關(guān)鍵字變色的方法
這篇文章顯示給大家介紹了字符串中關(guān)鍵字變色的實(shí)現(xiàn)方法,而后又拓展介紹了在Android中如何實(shí)現(xiàn)搜索關(guān)鍵字變色,相信對(duì)各位Android開(kāi)發(fā)者們具有一定的參考借鑒價(jià)值,感興趣的朋友們下面來(lái)一起看看吧。2016-10-10
解析Android游戲中獲取電話狀態(tài)進(jìn)行游戲暫?;蚶^續(xù)的解決方法
本篇文章是對(duì)在Android游戲中獲取電話狀態(tài)進(jìn)行游戲暫?;蚶^續(xù)的方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05
Android隨手筆記44之JSON數(shù)據(jù)解析
本文將主要介紹在Android開(kāi)發(fā)中,如何在服務(wù)器端創(chuàng)建JSON數(shù)據(jù),以及如何在Android客戶(hù)端對(duì)JSON數(shù)據(jù)進(jìn)行解析,對(duì)android json解析 相關(guān)知識(shí)感興趣的朋友一起學(xué)習(xí)吧2015-12-12
Flutter實(shí)現(xiàn)底部導(dǎo)航欄創(chuàng)建詳解
ConvexBottomBar是一個(gè)底部導(dǎo)航欄組件,用于展現(xiàn)凸起的TAB效果,支持多種內(nèi)置樣式與動(dòng)畫(huà)交互。本文將利用ConvexBottomBar創(chuàng)建漂亮的底部導(dǎo)航欄,感興趣的可以學(xué)習(xí)一下2022-01-01

