Android自定義View實(shí)現(xiàn)跟隨手指移動(dòng)
對(duì)View的移動(dòng),實(shí)現(xiàn)的方法有好幾種,原理是通過改變View的位置來移動(dòng)View,下面來實(shí)現(xiàn)這樣的效果
- 動(dòng)畫的方法
通過改變View的tranlationX和tranlationY的值來實(shí)現(xiàn)移動(dòng),首先來寫一個(gè)自定義View類,重寫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://離開事件 ?? ??? ?break; ?? ?default: ?? ??? ?break; }
通過判斷事件的類型,將在ACTION_MOVE事件中計(jì)算移動(dòng)前后的差值來設(shè)置View的translationX和translationY值來改變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方法來設(shè)置顯示的位置,可以通過這個(gè)方法來實(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ù),通過改變這個(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)畫實(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模糊處理實(shí)現(xiàn)圖片毛玻璃效果
這篇文章主要介紹了Android模糊處理實(shí)現(xiàn)圖片毛玻璃效果,需要的朋友可以參考下2016-02-02Android編程圖片加載類ImageLoader定義與用法實(shí)例分析
這篇文章主要介紹了Android編程圖片加載類ImageLoader定義與用法,結(jié)合實(shí)例形式分析了Android圖片加載類ImageLoader的功能、定義、使用方法及相關(guān)操作注意事項(xiàng),代碼中備有較為詳盡的注釋便于理解,需要的朋友可以參考下2017-12-12Android編程之桌面小部件AppWidgetProvider用法示例
這篇文章主要介紹了Android編程之桌面小部件AppWidgetProvider用法,結(jié)合具體實(shí)例形式分析了Android桌面組件AppWidgetProvider的功能、布局、權(quán)限設(shè)置等相關(guān)操作技巧,需要的朋友可以參考下2017-08-08Android中Xposed框架篇---修改系統(tǒng)位置信息實(shí)現(xiàn)自身隱藏功能實(shí)例
本篇文章介紹了Android中Xposed框架的使用,詳細(xì)的介紹了修改系統(tǒng)位置信息實(shí)現(xiàn)自身隱藏功能實(shí)例,有需要的朋友可以了解一下。2016-11-11詳解xamarin Android 實(shí)現(xiàn)ListView萬能適配器
這篇文章主要介紹了詳解xamarin Android 實(shí)現(xiàn)ListView萬能適配器的相關(guān)資料,這里主要實(shí)現(xiàn)listview 適配器的實(shí)例,需要的朋友可以參考下2017-08-08Flutter路由守衛(wèi)攔截的實(shí)現(xiàn)
路由守衛(wèi)攔截最常見的應(yīng)用場(chǎng)景就是對(duì)用戶數(shù)據(jù)權(quán)限的校驗(yàn),本文主要介紹了Flutter路由守衛(wèi)攔截的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-04-04Android實(shí)現(xiàn)志愿者系統(tǒng)詳細(xì)步驟與代碼
這篇文章主要介紹了Android實(shí)現(xiàn)志愿者系統(tǒng),本系統(tǒng)采用MVC架構(gòu)設(shè)計(jì),SQLite數(shù)據(jù)表有用戶表、成員表和活動(dòng)表,有十多個(gè)Activity頁面。打開應(yīng)用,進(jìn)入歡迎界面,3s后跳轉(zhuǎn)登錄界面,用戶先注冊(cè)賬號(hào),登錄成功后進(jìn)入主界面2023-02-02