开局一张图,先看看是不是想要的效果
没错,今天就要实现这种效果,首先,可以看出来,这个效果是由两部分组成的,滑动的view以及背景view.重点就是滑动的View,并且分两种情况,当滑动距离超过一半时,则顺势滑下去,没有超过一半,则回弹到初始位置。
对于View跟随手势去滑动,当然是ViewDragHelper是比较合适的。我对这个类我也是第一次用,里面还有很多东西没有理解,只是简单的去运用。主要是自定义View继承自LinearLayout.
贴代码,不多BB,看会应该都能懂。
public class SlideRightViewDragHelper extends LinearLayout {
private ViewDragHelper viewDragHelper;
private View child;
private Point childPosition = new Point();
private Point childEndPosition = new Point();
private OnReleasedListener onReleasedListener;
private int oldX;
public SlideRightViewDragHelper(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setTouchable(boolean isTouch) {
if (isTouch) {
//新建viewDragHelper ,viewGroup, 灵敏度,回调(子view的移动)
viewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
oldX = 0;
return true;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
oldX = left;
return Math.max(0, left);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (oldX > getWidth() / 2) {
/*
*之所以没这么写,是因为在滑到最右边之后,滑动的View就会被释放,我通过layout方法无法将view设置
*为复原,然后我必须又要把view在移回最左边,但无法实现向右顺势滑动的效果,反正达不到预期的效果,
*后来就自己写了个位移动画,最终实现了想要的效果。
*/
// viewDragHelper.settleCapturedViewAt(childEndPosition.x, childEndPosition.y);
// invalidate(); //必须刷新,因为其内部使用的是mScroller.startScroll,所以别忘了需要invalidate()以及结合computeScroll方法一起。
// if (onReleasedListener != null) {
// child.layout(childPosition.x, childPosition.y, getWidth(), getHeight());
// viewDragHelper.settleCapturedViewAt(childPosition.x, childPosition.y); //反弹
// onReleasedListener.onReleased();
// }
TranslateAnimation translateAnimation =
new TranslateAnimation(0, childEndPosition.x, childPosition.y, childPosition.y);
translateAnimation.setDuration(300);
child.startAnimation(translateAnimation);
translateAnimation.setAnimationListener(new Animation.AnimationListener() {
@Override
public void onAnimationStart(Animation animation) {
}
@Override
public void onAnimationEnd(Animation animation) {
Handler handler = new Handler();
handler.postDelayed(new Runnable() {
@Override
public void run() {
onReleasedListener.onReleased(0, 0, getWidth(), getHeight());
}
}, 10);
}
@Override
public void onAnimationRepeat(Animation animation) {
}
});
} else {//滑动距离不够一半,回到初始位置
viewDragHelper.settleCapturedViewAt(childPosition.x, childPosition.y); //反弹
invalidate();//必须调用
}
super.onViewReleased(releasedChild, xvel, yvel);
}
@Override
public void onViewCaptured(View capturedChild, int activePointerId) {
super.onViewCaptured(capturedChild, activePointerId);
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
super.onViewPositionChanged(changedView, left, top, dx, dy);
}
});
} else {
viewDragHelper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return false;
}
});
}
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
child = getChildAt(0);
}
@Override //用viewDragHelper拦截-true
public boolean onInterceptTouchEvent(MotionEvent ev) {
return viewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override //viewDragHelper拦截事件
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);
return true;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);
//定位左侧的坐标
childPosition.x = child.getLeft();
childPosition.y = child.getTop();
//定位右侧的坐标
childEndPosition.x = child.getRight();
childEndPosition.y = child.getTop();
}
@Override
public void computeScroll() {
super.computeScroll();
if (viewDragHelper.continueSettling(true)) {
invalidate();
}
}
public void setOnReleasedListener(OnReleasedListener onReleasedListener) {
this.onReleasedListener = onReleasedListener;
}
public interface OnReleasedListener {
void onReleased(int left, int top, int right, int bottom);
}
}
主要重写了ViewDragHelper的三个方法
tryCaptureView()试图要捕捉的View 当返回true时,可对当前View进行操作,返回false,则不可操作
clampViewPositionHorizontal() 在水平滑动过程中,可以得到当前View的left值
onViewReleased() 当手指抬起的时候回走这个方法,但我总觉得当我滑到最右边的时候,就会把我的View给释放掉,这个方法还不是很懂
当View滑动到最右边时,就会通过接口告知Activity当前view已经滑到最右边,实现这个接口,并作出对应的操作。
dragHelper.setOnReleasedListener(new SlideRightViewDragHelper.OnReleasedListener() {
@Override
public void onReleased(final int left, final int top, final int right, final int bottom) {
//自己的操作
}
});
把所有代码都贴一下
布局代码
Activity代码
public class SlideViewActivity extends AppCompatActivity implements View.OnClickListener {
SlideRightViewDragHelper dragHelper;
LinearLayout llSlideBg;
TextView tv;
Button bt;
boolean onLine = false;//false为离线 true为在线
boolean orderState = false; //false为未接单 true为接单
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_slide_view);
initView();
dragHelper.setOnReleasedListener(new SlideRightViewDragHelper.OnReleasedListener() {
@Override
public void onReleased(final int left, final int top, final int right, final int bottom) {
if (orderState == true) {//可接单状态——>不可接单状态
orderState = !orderState;
llSlideBg.setBackgroundColor(getResources().getColor(R.color.red));
} else {//不可接单状态——>可接单状态
orderState = !orderState;
llSlideBg.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
}
tv.setText(orderState == true ? ">>滑动结束听单" : ">>滑动开始听单");
dragHelper.setBackgroundColor(orderState == true ? getResources().getColor(R.color.red) : getResources().getColor(R.color.colorPrimary));
llSlideBg.layout(left, top, right, bottom);
}
});
}
private void initView() {
llSlideBg = findViewById(R.id.slide_view_ll);
tv = findViewById(R.id.slide_view_tv);
bt = findViewById(R.id.slide_view_bt);
dragHelper = findViewById(R.id.slide_view_drag_helper);
bt.setOnClickListener(this);
dragHelper.setTouchable(false);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.slide_view_bt:
if (onLine) {//当前为上线 去下线
onLine = !onLine;
llSlideBg.setBackgroundColor(getResources().getColor(R.color.gray));
dragHelper.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
bt.setText("上线");
dragHelper.setTouchable(false);
tv.setText(">>滑动开始听单");
dragHelper.recovery(llSlideBg);
} else {//当前为下线 去上线
onLine = !onLine;
llSlideBg.setBackgroundColor(getResources().getColor(R.color.red));
dragHelper.setBackgroundColor(getResources().getColor(R.color.colorPrimary));
bt.setText("下线");
dragHelper.setTouchable(true);
}
break;
}
}
}
到这里就结束了,这种功能也不是很难,前提是一定要多实践才行。加油