最近一个功能是定制特殊的刷新是拉伸特定布局,刷新状态标识也是特定的位置,我是重写了一个linearlayout–ParentCanOnTouchLinearLayout,但是由于子View有很多OnClick事件,导致父容器的(拉伸)滑动效果(onTouch事件失效)
本文旨在解决父子兼容,并没有封装死 刷新事件,开放了按下 和move中的产生的高度,和up的回调。
无论拉伸是采用什么逻辑,都只需要知道手下滑的距离,作为基本参数,然后按比例给你想要拉伸的布局设置params.height
考虑到我这里的实际场景 采用的是两个 view作为占位
<View
android:id="@+id/refreshZone1"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/main_color" />
<View
android:id="@+id/refreshZone2"
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@color/main_color" />
因为如果子view中有很多点击事件会导致父view onTouch事件失效我们需要在子view使其失效前,干掉子view的点击事件。
当然只是在满足我们上下拉的时候去干掉,其他的时候依然执行子view点击事件
private int yyy = -1;
private int xxx = -1;
private boolean isMove = false;
/**
* 核心方法
* @param event
* @return
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
isMove = false;
//此处为break所以返回值为false执行 子OnClick 所以父onTouch中没有Down 所以子view中初始化也要在move的第一个 坐标中获取
break;
case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP:
if (!isMove) {
return false;
}
Log.i("rex", "onInterceptTouchEvent --- ACTION_UP");
isMove = false;
break;
case MotionEvent.ACTION_MOVE:
if (!isMove) {
yyy = (int) event.getRawY();
xxx = (int) event.getRawX();
}
isMove = true;
Log.i("rex", "yyy --- " + yyy);
Log.i("rex", "onInterceptTouchEvent --- ACTION_MOVE");
Log.i("rex", "yyy --- " + yyy);
//细节优化 短距离移除
float moveY = event.getRawY();
float moveX = event.getRawX();
Log.i("rex", "moveY --- " + moveY);
Log.i("rex", "moveX --- " + moveX);
//如果是非点击事件就拦截 让父布局接手onTouch 否则执行子ViewOnClick
if (Math.abs(moveY - yyy) > dip2px(getContext(), 20) || Math.abs(moveX - xxx) > dip2px(getContext(), 20)) {
final ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(true);
}
Log.i("rex", "确定当前为父view滑动");
return true;
}
// if (Math.abs(moveY - yyy) < Math.abs(moveX - xxx)) {
// Log.i("rex", "onInterceptTouchEvent --- 横滑");
//// return false;
// }
break;
}
return false;
}
private OnPullDownImpl impl;
private boolean isNeedReresh;
private boolean isRefreshing;
private int y1 = -1;
private int max = 300;
private int height = -1;
private int paddingTop;
public interface OnPullDownImpl {
void moveHeight(int height);
void up();
void refreshHeigh();
}
public void setOnPullDownImpl(OnPullDownImpl impl) {
this.impl = impl;
}
public boolean isCanReresh() {
return isNeedReresh && !isRefreshing;
}
public void setRefreshing(boolean is) {
isRefreshing = is;
}
public boolean isRefreshing() {
return isRefreshing;
}
public void reSet() {
isRefreshing = false;
isNeedReresh = false;
y1 = -1;
height = -1;
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
//其实这里毫无意义,因为onInterceptTouchEvent为true 所以初始值应该在move中取
if (y1 == -1) {
isNeedReresh = false;
y1 = (int) event.getRawY();
}
Log.i("rex", "onTouchEvent --- ACTION_DOWN y1===" + y1);
break;
case MotionEvent.ACTION_MOVE:
if (y1 == -1) {
//当为子View Ontouch时候 可能不走上面的down
isNeedReresh = false;
y1 = (int) event.getRawY();
}
height = (int) event.getRawY() - y1;
Log.i("rex", "height=====" + height);
if (height > 120) {
isNeedReresh = true;
impl.refreshHeigh();
}
if (0 < height && height < max) {
if (impl != null) {
//下拉
impl.moveHeight(height);
}
}
if (height < 0) {
//底部拉伸
if (height < -max) {
height = -max;
}
setPadding(0, height, 0, 0);
}
break;
case MotionEvent.ACTION_UP:
Log.i("rex", "ACTION_UP");
if (impl != null) {
//拓展
impl.up();
}
paddingTop = getPaddingTop();
if (paddingTop < 0) {
//底部回弹
if (mRunnable != null) {
removeCallbacks(mRunnable);
mRunnable = null;
}
mRunnable = runnable;
postDelayed(mRunnable, 20);
}
break;
}
return true;
}
private Runnable mRunnable = null;
//循环回弹的Runnable
private Runnable runnable = new Runnable() {
@Override
public void run() {
paddingTop = paddingTop + 20;
if (paddingTop > -6) {
setPadding(0, 0, 0, 0);
} else {
setPadding(0, paddingTop, 0, 0);
postDelayed(this, 20);
}
}
};
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
/**
* 设置界面更新
*/
int y = -1;
private Runnable mRunnable = null;
private void setRootRresh() {
/**
* 初始化 自定义刷新控件
*/
ballView2 = (BallView2) view.findViewById(R.id.ballView2);
llRefreshRex = (ParentCanOnTouchLinearLayout) view.findViewById(R.id.llRefreshRex);
final View view1 = view.findViewById(R.id.refreshZone1);
final View view2 = view.findViewById(R.id.refreshZone2);
final ViewGroup.LayoutParams lp = view1.getLayoutParams();
final Runnable runnable = new Runnable() {
@Override
public void run() {
lp.height = lp.height - 10;
view1.setLayoutParams(lp);
view2.setLayoutParams(lp);
if (lp.height < 6) {
lp.height = 0;
view1.setLayoutParams(lp);
view2.setLayoutParams(lp);
y = -1;
if (llRefreshRex.isCanReresh()) {
llRefreshRex.setRefreshing(true);
Log.i("rex", "请求刷新!");
initDatas();
} else if (llRefreshRex.isRefreshing()) {
//不做处理
Log.i("rex", "正在刷新中");
} else {
//不刷新
ballView2.setVisibility(View.GONE);
llRefreshRex.reSet();
}
} else {
view1.postDelayed(this, 20);
}
}
};
llRefreshRex.setOnPullDownImpl(new ParentCanOnTouchLinearLayout.OnPullDownImpl() {
@Override
public void moveHeight(int height) {
lp.height = height / 3;
view1.setLayoutParams(lp);
view2.setLayoutParams(lp);
}
@Override
public void refreshHeigh() {
ballView2.setVisibility(View.VISIBLE);
}
@Override
public void up() {
if (mRunnable != null) {
view1.removeCallbacks(mRunnable);
mRunnable = null;
}
mRunnable = runnable;
view1.postDelayed(mRunnable, 20);
}
});
}