- 关于侧滑效果,github上面已经有了很多成型的框架。可以非常方便的集成使用。
- 不过,实际项目中,可能有些需求,框架并没有帮我们完成。所以,有时候,需要自己动手实现这样的效果。
- 根据泡网,hongyang,还有Android群英传,以及网上各位大婶的博客文章。我写了一个简单的侧滑效果。
- 记录在此,主要是加深印象。详情在代码注释中
/**
* Created on 2017/1/24.
*/
public class VdbGroup extends FrameLayout {
private ViewDragHelper helper;
private View firstView;
private View secondView;
public VdbGroup get() {
return this;
}
public VdbGroup(Context context) {
this(context, null);
}
public VdbGroup(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
// record init position of second view
}
public VdbGroup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
helper = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == secondView;
}
// target child can scroll in x when touch move
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftBound = firstView.getLeft(); // MainView侧滑的起点
final int rightBound = firstView.getMeasuredWidth() - leftBound + 10; // 终点 +10 是为了看到效果,实际使用中 去掉 +10 的操作
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
LogUtils.e("newL = " + newLeft + " rb = " + rightBound);
return newLeft;
}
// 子View 可点击的时候需要重新的方法
@Override
public int getViewHorizontalDragRange(View child) {
return getMeasuredWidth() - firstView.getMeasuredWidth();
}
// 当松手之后的回调
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
// when release let it go back of the init position
int secondLeft = secondView.getLeft();
int middle = (firstView.getLeft() + firstView.getRight()) / 2;
LogUtils.e("secondLeft = " + secondLeft + " menuRight = "
+ firstView.getRight() + " menuL = " + firstView.getLeft());
if (secondLeft > middle) {
// open
helper.smoothSlideViewTo(releasedChild, firstView.getRight(), firstView.getTop());
ViewCompat.postInvalidateOnAnimation(get());
} else {
// close
helper.smoothSlideViewTo(releasedChild, firstView.getLeft(), firstView.getTop());
ViewCompat.postInvalidateOnAnimation(get());
}
}
});
}
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (getChildCount() != 2) {
throw new RuntimeException("I had two children,where they are?");
}
firstView = getChildAt(0);
firstView.setVisibility(VISIBLE);
secondView = getChildAt(1);
secondView.setVisibility(VISIBLE);
}
@Override
public void computeScroll() {
if (helper.continueSettling(true)) {
ViewCompat.postInvalidateOnAnimation(this);
}
}
@Override
public boolean onTouchEvent(MotionEvent event) {
helper.processTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return helper.shouldInterceptTouchEvent(ev);
}
}
- 简单介绍一下
getViewHorizontalDragRange(View child)
方法:
// 子View 可点击的时候需要重新的方法
@Override
public int getViewHorizontalDragRange(View child) {
return getMeasuredWidth() - firstView.getMeasuredWidth();
}
这个方法,在子View可点击的时候需要重写。返回值>0,才可以拖动。
- 还有这个方法
clampViewPositionHorizontal(View child, int left, int dx)
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftBound = firstView.getLeft(); // MainView侧滑的起点
final int rightBound = firstView.getMeasuredWidth() - leftBound + 10; // 终点
final int newLeft = Math.min(Math.max(left, leftBound), rightBound);
LogUtils.e("newL = " + newLeft + " rb = " + rightBound);
return newLeft;
}
如果只是需要滑动效果,直接返回
left
即可。但是这里为了搞侧滑效果。所以,是希望她的滑动范围是MenuView
的宽度。而int newLeft = Math.min(Math.max(left, leftBound), rightBound);
这句代码的作用就是,如果left
在指定的范围内,就返回left
,否则就返回边界值。
- 更多的关于
ViewDragHelper
的介绍,我就不介绍了。上面给出的链接都有详细的解释。 - 好了,这样子,一个简单的侧滑效果就实现了,总体不到120行代码。