欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Android自定義View實現(xiàn)拖動自動吸邊效果

 更新時間:2022年06月28日 10:52:43   作者:Android師哥  
這篇文章主要為大家詳細(xì)介紹了Android自定義View實現(xiàn)拖動自動吸邊效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價值,感興趣的小伙伴們可以參考一下

本文實例為大家分享了Android自定義View實現(xiàn)拖動自動吸邊的具體代碼,供大家參考,具體內(nèi)容如下

自定義View,一是為了滿足設(shè)計需求,二是開發(fā)者進(jìn)階的標(biāo)志之一。隨心所欲就是我等奮斗的目標(biāo)?。?!

效果

實現(xiàn)邏輯

明確需求

1、實現(xiàn)控件跟隨手指拖動
2、實現(xiàn)控件自動貼邊

整理思路

1、既然要實現(xiàn)控件拖動,那么就離不開onTouchEvent()這個方法,需要監(jiān)聽里面的按下和滑動事件。
2、 要實現(xiàn)自動貼邊,需要監(jiān)聽onTouchEvent()中手指離開屏幕事件。對于貼邊的過程,我們用屬性動畫來解決。
3、事件的沖突問題也需要考慮,拖動、點擊關(guān)系到了事件的攔截。

動手實現(xiàn)

在需求明確、思路清晰的情況下就要開始動手實現(xiàn)(需要了解自定義View的一些基礎(chǔ)API),下面代碼中注釋寫的基本都差不多,很好理解。歡迎指出討論?。?!

完整代碼

Kotlin

class AttachButton: View {
? ? private var mLastRawX: Float = 0F
? ? private var mLastRawY: Float = 0F
? ? private var isDrug = false
? ? private var mRootMeasuredWidth = 0
? ? private var mRootMeasuredHeight = 0
? ? private var mRootTopY = 0
? ? private var customIsAttach = false
? ? private var customIsDrag = false

? ? constructor(context: Context) : this(context, null)
? ? constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)
? ? constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
? ? ? ? context,
? ? ? ? attrs,
? ? ? ? defStyleAttr
? ? ) {
? ? ? ? isClickable = true
? ? ? ? initAttrs(context, attrs)
? ? }

? ? private fun initAttrs(context: Context, attrs: AttributeSet?) {
? ? ? ? attrs?.let {
? ? ? ? ? ? val mTypedAttay = context.obtainStyledAttributes(it, R.styleable.AttachButton)
? ? ? ? ? ? customIsAttach =
? ? ? ? ? ? ? ? mTypedAttay.getBoolean(R.styleable.AttachButton_customIsAttach, true)
? ? ? ? ? ? customIsDrag =
? ? ? ? ? ? ? ? mTypedAttay.getBoolean(R.styleable.AttachButton_customIsDrag, true)
? ? ? ? ? ? mTypedAttay.recycle()
? ? ? ? }
? ? }

? ? override fun dispatchTouchEvent(event: MotionEvent?): Boolean {
? ? ? ? super.dispatchTouchEvent(event)
? ? ? ? return true
? ? }

? ? override fun onTouchEvent(event: MotionEvent?): Boolean {
? ? ? ? event?.let {
? ? ? ? ? ? //判斷是否需要滑動
? ? ? ? ? ? if (customIsDrag) {
? ? ? ? ? ? ? ? //當(dāng)前手指的坐標(biāo)
? ? ? ? ? ? ? ? val mRawX = it.rawX
? ? ? ? ? ? ? ? val mRawY = it.rawY
? ? ? ? ? ? ? ? when (it.action) {
? ? ? ? ? ? ? ? ? ? MotionEvent.ACTION_DOWN -> {//手指按下
? ? ? ? ? ? ? ? ? ? ? ? isDrug = false
? ? ? ? ? ? ? ? ? ? ? ? //記錄按下的位置
? ? ? ? ? ? ? ? ? ? ? ? mLastRawX = mRawX
? ? ? ? ? ? ? ? ? ? ? ? mLastRawY = mRawY
? ? ? ? ? ? ? ? ? ? ? ? if (parent is ViewGroup) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? val mViewGroup = parent as ViewGroup
? ? ? ? ? ? ? ? ? ? ? ? ? ? val location = IntArray(2)
? ? ? ? ? ? ? ? ? ? ? ? ? ? mViewGroup.getLocationInWindow(location)
? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲取父布局的高度
? ? ? ? ? ? ? ? ? ? ? ? ? ? mRootMeasuredHeight = mViewGroup.measuredHeight
? ? ? ? ? ? ? ? ? ? ? ? ? ? mRootMeasuredWidth = mViewGroup.measuredWidth
? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲取父布局頂點的坐標(biāo)
? ? ? ? ? ? ? ? ? ? ? ? ? ? mRootTopY = location[1]
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? MotionEvent.ACTION_MOVE -> {//手指滑動
? ? ? ? ? ? ? ? ? ? ? ? if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //手指X軸滑動距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val differenceValueX: Float = mRawX - mLastRawX
? ? ? ? ? ? ? ? ? ? ? ? ? ? //手指Y軸滑動距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val differenceValueY: Float = mRawY - mLastRawY
? ? ? ? ? ? ? ? ? ? ? ? ? ? //判斷是否為拖動操作
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (!isDrug) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isDrug =
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? sqrt(((differenceValueX * differenceValueX) + (differenceValueY * differenceValueY)).toDouble()) >= 2
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲取手指按下的距離與控件本身X軸的距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val ownX = x
? ? ? ? ? ? ? ? ? ? ? ? ? ? //獲取手指按下的距離與控件本身Y軸的距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val ownY = y
? ? ? ? ? ? ? ? ? ? ? ? ? ? //理論中X軸拖動的距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? var endX: Float = ownX + differenceValueX
? ? ? ? ? ? ? ? ? ? ? ? ? ? //理論中Y軸拖動的距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? var endY: Float = ownY + differenceValueY
? ? ? ? ? ? ? ? ? ? ? ? ? ? //X軸可以拖動的最大距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val maxX: Float = mRootMeasuredWidth - width.toFloat()
? ? ? ? ? ? ? ? ? ? ? ? ? ? //Y軸可以拖動的最大距離
? ? ? ? ? ? ? ? ? ? ? ? ? ? val maxY: Float = mRootMeasuredHeight - height.toFloat()
? ? ? ? ? ? ? ? ? ? ? ? ? ? //X軸邊界限制
? ? ? ? ? ? ? ? ? ? ? ? ? ? endX = if (endX < 0) 0F else (if (endX > maxX) maxX else endX)
? ? ? ? ? ? ? ? ? ? ? ? ? ? //Y軸邊界限制
? ? ? ? ? ? ? ? ? ? ? ? ? ? endY = if (endY < 0) 0F else (if (endY > maxY) maxY else endY)
? ? ? ? ? ? ? ? ? ? ? ? ? ? //開始移動
? ? ? ? ? ? ? ? ? ? ? ? ? ? x = endX
? ? ? ? ? ? ? ? ? ? ? ? ? ? y = endY
? ? ? ? ? ? ? ? ? ? ? ? ? ? //記錄位置
? ? ? ? ? ? ? ? ? ? ? ? ? ? mLastRawX = mRawX
? ? ? ? ? ? ? ? ? ? ? ? ? ? mLastRawY = mRawY
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? MotionEvent.ACTION_UP -> {//手指離開
? ? ? ? ? ? ? ? ? ? ? ? if (customIsAttach) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? //判斷是否為點擊事件
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (isDrug) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? val center = mRootMeasuredWidth / 2
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //自動貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? if (mLastRawX <= center) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //向左貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animate()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setInterpolator(BounceInterpolator())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setDuration(500)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .x(0F)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .start()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //向右貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? animate()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setInterpolator(BounceInterpolator())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setDuration(500)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .x(mRootMeasuredWidth - width.toFloat())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .start()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? }
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //是否攔截事件
? ? ? ? return if (isDrug) isDrug else super.onTouchEvent(event)
? ? }
}

Java

/**
?* 自定義View實現(xiàn)拖動并自動吸邊效果
?* <p>
?* 處理滑動和貼邊 {@link #onTouchEvent(MotionEvent)}
?* 處理事件分發(fā) {@link #dispatchTouchEvent(MotionEvent)}
?* </p>
?*
?* @attr customIsAttach ?//是否需要自動吸邊
?* @attr customIsDrag ? ?//是否可拖曳
?*/
public class AttachButton extends View {
? ? private float mLastRawX;
? ? private float mLastRawY;
? ? private final String TAG = "AttachButton";
? ? private boolean isDrug = false;
? ? private int mRootMeasuredWidth = 0;
? ? private int mRootMeasuredHeight = 0;
? ? private int mRootTopY = 0;
? ? private boolean customIsAttach;
? ? private boolean customIsDrag;

? ? public AttachButton(Context context) {
? ? ? ? this(context, null);
? ? }

? ? public AttachButton(Context context, @Nullable AttributeSet attrs) {
? ? ? ? this(context, attrs, 0);
? ? }

? ? public AttachButton(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
? ? ? ? super(context, attrs, defStyleAttr);
? ? ? ? setClickable(true);
? ? ? ? initAttrs(context, attrs);
? ? }

? ? /**
? ? ?* 初始化自定義屬性
? ? ?*/
? ? private void initAttrs(Context context, AttributeSet attrs) {
? ? ? ? TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachButton);
? ? ? ? customIsAttach = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsAttach, true);
? ? ? ? customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachButton_customIsDrag, true);
? ? ? ? mTypedAttay.recycle();
? ? }

? ? @Override
? ? public boolean dispatchTouchEvent(MotionEvent event) {
? ? ? ? super.dispatchTouchEvent(event);
? ? ? ? return true;
? ? }

? ? @Override
? ? public boolean onTouchEvent(MotionEvent ev) {
? ? ? ? //判斷是否需要滑動
? ? ? ? if (customIsDrag) {
? ? ? ? ? ? //當(dāng)前手指的坐標(biāo)
? ? ? ? ? ? float mRawX = ev.getRawX();
? ? ? ? ? ? float mRawY = ev.getRawY();
? ? ? ? ? ? switch (ev.getAction()) {
? ? ? ? ? ? ? ? case MotionEvent.ACTION_DOWN://手指按下
? ? ? ? ? ? ? ? ? ? isDrug = false;
? ? ? ? ? ? ? ? ? ? //記錄按下的位置
? ? ? ? ? ? ? ? ? ? mLastRawX = mRawX;
? ? ? ? ? ? ? ? ? ? mLastRawY = mRawY;
? ? ? ? ? ? ? ? ? ? ViewGroup mViewGroup = (ViewGroup) getParent();
? ? ? ? ? ? ? ? ? ? if (mViewGroup != null) {
? ? ? ? ? ? ? ? ? ? ? ? int[] location = new int[2];
? ? ? ? ? ? ? ? ? ? ? ? mViewGroup.getLocationInWindow(location);
? ? ? ? ? ? ? ? ? ? ? ? //獲取父布局的高度
? ? ? ? ? ? ? ? ? ? ? ? mRootMeasuredHeight = mViewGroup.getMeasuredHeight();
? ? ? ? ? ? ? ? ? ? ? ? mRootMeasuredWidth = mViewGroup.getMeasuredWidth();
? ? ? ? ? ? ? ? ? ? ? ? //獲取父布局頂點的坐標(biāo)
? ? ? ? ? ? ? ? ? ? ? ? mRootTopY = location[1];
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case MotionEvent.ACTION_MOVE://手指滑動
? ? ? ? ? ? ? ? ? ? if (mRawX >= 0 && mRawX <= mRootMeasuredWidth && mRawY >= mRootTopY && mRawY <= (mRootMeasuredHeight + mRootTopY)) {
? ? ? ? ? ? ? ? ? ? ? ? //手指X軸滑動距離
? ? ? ? ? ? ? ? ? ? ? ? float differenceValueX = mRawX - mLastRawX;
? ? ? ? ? ? ? ? ? ? ? ? //手指Y軸滑動距離
? ? ? ? ? ? ? ? ? ? ? ? float differenceValueY = mRawY - mLastRawY;
? ? ? ? ? ? ? ? ? ? ? ? //判斷是否為拖動操作
? ? ? ? ? ? ? ? ? ? ? ? if (!isDrug) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (Math.sqrt(differenceValueX * differenceValueX + differenceValueY * differenceValueY) < 2) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isDrug = false;
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? isDrug = true;
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? //獲取手指按下的距離與控件本身X軸的距離
? ? ? ? ? ? ? ? ? ? ? ? float ownX = getX();
? ? ? ? ? ? ? ? ? ? ? ? //獲取手指按下的距離與控件本身Y軸的距離
? ? ? ? ? ? ? ? ? ? ? ? float ownY = getY();
? ? ? ? ? ? ? ? ? ? ? ? //理論中X軸拖動的距離
? ? ? ? ? ? ? ? ? ? ? ? float endX = ownX + differenceValueX;
? ? ? ? ? ? ? ? ? ? ? ? //理論中Y軸拖動的距離
? ? ? ? ? ? ? ? ? ? ? ? float endY = ownY + differenceValueY;
? ? ? ? ? ? ? ? ? ? ? ? //X軸可以拖動的最大距離
? ? ? ? ? ? ? ? ? ? ? ? float maxX = mRootMeasuredWidth - getWidth();
? ? ? ? ? ? ? ? ? ? ? ? //Y軸可以拖動的最大距離
? ? ? ? ? ? ? ? ? ? ? ? float maxY = mRootMeasuredHeight - getHeight();
? ? ? ? ? ? ? ? ? ? ? ? //X軸邊界限制
? ? ? ? ? ? ? ? ? ? ? ? endX = endX < 0 ? 0 : endX > maxX ? maxX : endX;
? ? ? ? ? ? ? ? ? ? ? ? //Y軸邊界限制
? ? ? ? ? ? ? ? ? ? ? ? endY = endY < 0 ? 0 : endY > maxY ? maxY : endY;
? ? ? ? ? ? ? ? ? ? ? ? //開始移動
? ? ? ? ? ? ? ? ? ? ? ? setX(endX);
? ? ? ? ? ? ? ? ? ? ? ? setY(endY);
? ? ? ? ? ? ? ? ? ? ? ? //記錄位置
? ? ? ? ? ? ? ? ? ? ? ? mLastRawX = mRawX;
? ? ? ? ? ? ? ? ? ? ? ? mLastRawY = mRawY;
? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? ? ? case MotionEvent.ACTION_UP://手指離開
? ? ? ? ? ? ? ? ? ? //根據(jù)自定義屬性判斷是否需要貼邊
? ? ? ? ? ? ? ? ? ? if (customIsAttach) {
? ? ? ? ? ? ? ? ? ? ? ? //判斷是否為點擊事件
? ? ? ? ? ? ? ? ? ? ? ? if (isDrug) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? float center = mRootMeasuredWidth / 2;
? ? ? ? ? ? ? ? ? ? ? ? ? ? //自動貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? if (mLastRawX <= center) {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //向左貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AttachButton.this.animate()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setInterpolator(new BounceInterpolator())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setDuration(500)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .x(0)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .start();
? ? ? ? ? ? ? ? ? ? ? ? ? ? } else {
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? //向右貼邊
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? AttachButton.this.animate()
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setInterpolator(new BounceInterpolator())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .setDuration(500)
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .x(mRootMeasuredWidth - getWidth())
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? .start();
? ? ? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? }
? ? ? ? ? ? ? ? ? ? break;
? ? ? ? ? ? }
? ? ? ? }
? ? ? ? //是否攔截事件
? ? ? ? return isDrug ? isDrug : super.onTouchEvent(ev);
? ? }
}

自定義屬性

<declare-styleable name="AttachButton">
? ? ? ? <!--是否需要自動吸邊-->
? ? ? ? <attr name="customIsAttach" format="boolean" />
? ? ? ? <!--是否可拖曳-->
? ? ? ? <attr name="customIsDrag" format="boolean" />
</declare-styleable>

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論