package com.xin.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewPropertyAnimator;
import android.view.animation.BounceInterpolator;
import android.widget.LinearLayout;
import androidx.annotation.Nullable;
import com.hrg.hefei.R;
/**
* 自定義View實現(xiàn)拖動并自動吸邊效果
* <p>
* 處理滑動和貼邊 {@link #onTouchEvent(MotionEvent)}
* 處理事件分發(fā) {@link #dispatchTouchEvent(MotionEvent)}
* </p>
*
* @attr customIsAttach //是否需要自動吸邊
* @attr customIsDrag //是否可拖曳
*/
public class AttachLayout extends LinearLayout {
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 int customAttachDirect; /*-1不吸附 0所有的邊 1左 2上 3右 4下 5左右 6上下 */
private boolean customIsDrag;
private boolean touchIsTargetView = true;
private int customIsTargetView;
private View targetView;
public AttachLayout(Context context) {
this(context, null);
}
public AttachLayout(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public AttachLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initAttrs(context, attrs);
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (customIsTargetView > 0) {
targetView = findViewById(customIsTargetView);
}
}
/**
* 初始化自定義屬性
*/
private void initAttrs(Context context, AttributeSet attrs) {
TypedArray mTypedAttay = context.obtainStyledAttributes(attrs, R.styleable.AttachLayout);
customAttachDirect = mTypedAttay.getInteger(R.styleable.AttachLayout_customAttachDirect, 0);
customIsDrag = mTypedAttay.getBoolean(R.styleable.AttachLayout_customIsDrag, true);
customIsTargetView = mTypedAttay.getResourceId(R.styleable.AttachLayout_customIsTargetView, 0);
mTypedAttay.recycle();
}
@Override
public boolean dispatchTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
touchIsTargetView = true;
}
if (targetView != null) {
// /*判斷是否有目標(biāo)view,若有不在目標(biāo)view內(nèi)不執(zhí)行*/
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://手指按下
Rect rect = new Rect();
targetView.getHitRect(rect);
if (!rect.contains((int) event.getX(), (int) event.getY())) {
touchIsTargetView = false;
}
}
}
if (touchIsTargetView) {
doTouch(event);
}
return super.dispatchTouchEvent(event);
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
//判斷是否需要滑動
// doTouch(ev); /*不能放在這公般,放在這子view收不到事件了*/
//是否攔截事件
if (isDrug) {
return true;
}
return super.onTouchEvent(ev);
}
private void doTouch(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 (customAttachDirect >= 0 && isDrug) {
//判斷是否為點擊事件 0所有的邊 1左 2上 3右 4下 5左右 6上下
float centerX = mRootMeasuredWidth / 2;
float centerY = mRootMeasuredHeight / 2;
float x = -1, y = -1;
if (customAttachDirect == 1) { /*左*/
x = 0;
y = -1;
} else if (customAttachDirect == 2) { /*上*/
x = -1;
y = 0;
} else if (customAttachDirect == 3) { /*右*/
x = mRootMeasuredWidth - getWidth();
y = -1;
} else if (customAttachDirect == 4) {
x = -1;
y = mRootMeasuredWidth - getHeight();
} else if (customAttachDirect == 5) { /*左右*/
x = mLastRawX <= centerX ? 0 : (mRootMeasuredWidth - getWidth());
y = -1;
} else if (customAttachDirect == 6) { /*上下*/
x = -1;
y = mLastRawY <= centerY ? 0 : (mRootMeasuredHeight - getHeight());
} else if (customAttachDirect == 0) { /*距那個邊近去那個*/
// TODO: 2020/5/28 0028
}
//自動貼邊
ViewPropertyAnimator animator = AttachLayout.this.animate()
.setInterpolator(new BounceInterpolator())
.setDuration(500);
if (x >= 0) {
animator.x(x);
}
if (y >= 0) {
animator.y(y);
}
animator.start();
}
break;
}
}
}
}
android AttachLayout 拖動吸邊效果
最后編輯于 :
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
- 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人审孽,你說我怎么就攤上這事县袱。” “怎么了佑力?”我有些...
- 文/不壞的土叔 我叫張陵式散,是天一觀的道長。 經(jīng)常有香客問我打颤,道長暴拄,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任瘸洛,我火速辦了婚禮揍移,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘反肋。我一直安慰自己那伐,他們只是感情好,可當(dāng)我...
- 文/花漫 我一把揭開白布石蔗。 她就那樣靜靜地躺著罕邀,像睡著了一般。 火紅的嫁衣襯著肌膚如雪养距。 梳的紋絲不亂的頭發(fā)上诉探,一...
- 文/蒼蘭香墨 我猛地睜開眼束析,長吁一口氣:“原來是場噩夢啊……” “哼艳馒!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起员寇,我...
- 正文 年R本政府宣布,位于F島的核電站飒赃,受9級特大地震影響利花,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜载佳,卻給世界環(huán)境...
- 文/蒙蒙 一炒事、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧蔫慧,春花似錦挠乳、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至黍析,卻和暖如春卖怜,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背阐枣。 一陣腳步聲響...