自定义ViewGroup
程序员文章站
2022-06-08 17:36:18
...
ViewGroup存在的意义就是为了对其子View 进行管理, 为其子View 添加显示, 响应的规则。 因此通常需要重写 onMeasure() 对子View 进行测量, 重写 onLayout() 方法来确定子View 的位置, 重写onTouchEvent() 方法增加响应事件。 通过下面例子, 实现一个类似ScrollView 的自定义 ViewGroup, 在ViewGroup 能够滚动之前, 需要先放置好它的子View。 使用遍历的方式来通知子 View对自身进行测量。
@Override
protected void onMeasure(int widthMeasureSpec,
int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int count = getChildCount();
for (int i = 0; i < count; ++i) {
View childView = getChildAt(i);
measureChild(childView,
widthMeasureSpec, heightMeasureSpec);
}
}
接下来对子View 进行放置位置的设定。 让每个子View 都显示完整的一屏, 这样在滑动的时候, 可以比较好的实现后面的效果。 View 的高度为子View 的个数 * 屏幕高度。
// 设置ViewGroup的高度
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = mScreenHeight * childCount;
setLayoutParams(mlp);
通过调用子View 的layout()方法, 将其具体位置作为参数传递进去即可, 代码如下:
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount = getChildCount();
// 设置ViewGroup的高度
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = mScreenHeight * childCount;
setLayoutParams(mlp);
for (int i = 0; i < childCount; i++) {
View child = getChildAt(i);
if (child.getVisibility() != View.GONE) {
child.layout(l, i * mScreenHeight, r, (i + 1) * mScreenHeight);
}
}
}
将子View 放置到ViewGroup 后, 重写 OntouchEvent() ,为ViewGroup 添加响应事件。
@Override
public boolean onTouchEvent(MotionEvent event) {
int y = (int) event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mLastY = y;
mStart = getScrollY();
break;
case MotionEvent.ACTION_MOVE:
if (!mScroller.isFinished()) {
mScroller.abortAnimation();
}
int dy = mLastY - y;
if (getScrollY() < 0) {
dy = 0;
}
if (getScrollY() > getHeight() - mScreenHeight) {
dy = 0;
}
scrollBy(0, dy);
mLastY = y;
break;
case MotionEvent.ACTION_UP:
int dScrollY = checkAlignment();
if (dScrollY > 0) {
if (dScrollY < mScreenHeight / 3) {
mScroller.startScroll(
0, getScrollY(),
0, -dScrollY);
} else {
mScroller.startScroll(
0, getScrollY(),
0, mScreenHeight - dScrollY);
}
} else {
if (-dScrollY < mScreenHeight / 3) {
mScroller.startScroll(
0, getScrollY(),
0, -dScrollY);
} else {
mScroller.startScroll(
0, getScrollY(),
0, -mScreenHeight - dScrollY);
}
}
break;
}
postInvalidate();
return true;
}
通过上面操作, 就可以完成滚动逻辑和“粘性”的逻辑。
最后加上:
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}
-------------------------------------------------------------