自定义控件之侧滑菜单SlidingViewGroup
github地址:https://github.com/mingC0758/SlidingViewGroup
本文主要介绍实现一个侧滑菜单的过程。利用ViewGroup来实现,并且具有强扩展性,用户可以自定义主要内容视图和侧滑菜单视图,并妥善处理了父View跟子View的滑动冲突问题。
灵感来源与需求
灵感主要来自TIM的聊天信息的滑动菜单:
需求:
- ViewGroup允许用户放入两个视图,一个作为内容视图,一个作为菜单视图。
- 滑动距离或速度大于阈值时滑出菜单
- 在菜单视图中进行滑动时不响应菜单的点击事件
实现过程
常量定义:
/**
* 滑动距离占副View比值阈值,超过自动滑出
*/
private final float SCROLL_DISTANCE_SHREHOLD = 0.2f;
/**
* 速度阈值,超过这个数自动滑出
*/
private final float SCROLL_SPEED_SHREHOLD = 500;
定义了一个滑动距离阈值和一个滑动速度阈值,任意一个超过了都进行滑动操作。
定义状态:
/**
* 状态
*/
private State mState = State.AT_FIRST;
private enum State {
AT_FIRST, AT_SECOND
}
AT_FIRST:在内容视图;
AT_SECOND:在菜单视图。
测量ViewGroup大小,如果ViewGroup指定了大小,则设置为指定大小,否则设置为子View中的最大值:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int widthMode = getMode(widthMeasureSpec);
int heightMode = getMode(heightMeasureSpec);
//只测量前两个子View,其他的忽视
int childCount = getChildCount();
if (childCount > 0) {
//测量子View1
measureChild(getChildAt(0), widthMeasureSpec, heightMeasureSpec);
}
if (childCount > 1) {
//测量子View2,宽度限定为本容器的特定比例
int slidingViewMS = MeasureSpec.makeMeasureSpec((int) (widthSize * mMenuWidthRadio),
widthMode);
measureChild(getChildAt(1), slidingViewMS, heightMeasureSpec);
}
//计算子View中的最高和最宽
int maxH = 0;
int maxW = 0;
if (childCount > 1) {
int h1 = getChildAt(0).getMeasuredHeight();
int h2 = getChildAt(1).getMeasuredHeight();
maxH = h1 > h2 ? h1 : h2;
int w1 = getChildAt(0).getMeasuredWidth();
int w2 = getChildAt(1).getMeasuredWidth();
maxW = w1 > w2 ? w1 : w2;
} else if (childCount > 0) {
maxW = getChildAt(0).getMeasuredWidth();
maxH = getChildAt(0).getMeasuredHeight();
}
//根据ViewGroup的要求来选择大小
if (widthMode == AT_MOST && heightMode == AT_MOST) {
setMeasuredDimension(maxW < widthSize ? maxW : widthSize,
maxH < heightSize ? maxH : heightSize);
} else if (widthMode == AT_MOST) {
setMeasuredDimens