自定义ViewGroup
自定义ViewGroup
ViewGroup就是对子View的管理
自定义ViewGroup需要重写onMeasure()方法对子View测量,重写onLayout()方法来确定子View的位置,重写onTouchEvent()方法响应事件
测量子View的方法
measureChild(childView, widthMeasureSpec, heightMeasureSpec);
布局中设置ViewGroup的高度
MarginLayoutParams mlp = (MarginLayoutParams) getLayoutParams();
mlp.height = mScreenHeight * childCount;
setLayoutParams(mlp);
响应事件这里使用了滑动
Scroller计算坐标的工具类,它的响应过程是
scrollTo()/scrollBy() ---> invalidate()/postInvalidate() ---> computeScroll()
这个过程是没有动画效果的,只是更新了坐标位置
使用动画的滑动,是通过startScroll,系统不断回调computeScroll,在回调中不断执行scrollTo,形成动画效果
完整代码
/*
*
* 1、首先测量子View
* onMeasure中进行
* 2、View的位置摆放
* 这里每个子View占一屏,在onLayout中进行
* 在初始化中我们得到屏幕的相关参数
* 3、滑动监听事件
* 重写onTouchEvent方法,这里使用了Scroller的方法来滑动
*
*/
public class MyScrollView extends ViewGroup{
private final int mScreenHeight;
private final Scroller mScroller;
private int mLastY;
private int mStart;
private int mEnd;
public MyScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
DisplayMetrics dm = new DisplayMetrics();
wm.getDefaultDisplay().getMetrics(dm);
mScreenHeight = dm.heightPixels;
// Scroller是一个计算坐标的工具类。其实Scroller与View的滑动是没有关系的,它只是计算在动画执行某个时间所在的某个位置的坐标,这样就形成了坐标路线,再view根据坐标路线循环invalidate在界上新显示,就形成了我们看到的平滑移动了
mScroller = new Scroller(context);
}
@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);
}
}
@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);
}
}
}
@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();
}
// 滑动的距离,scrollY不能小于0,也不能大于最后一屏高度
int dy = mLastY - y;
if(getScrollY() < 0){
dy = 0;
}
if(getScrollY() > getHeight() - mScreenHeight){
dy = 0;
}
// scrollTo()/scrollBy() ---> invalidate()/postInvalidate() ---> computeScroll()
scrollBy(0, dy);
mLastY = y;
break;
case MotionEvent.ACTION_UP:
mEnd = getScrollY();
int dScrollY = mEnd - mStart;
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;
}
/**
* startScroll()只是开始动画,如果computeScroll()方法不实现则没有任何效果,值是为了给后面视图移动添加一些动画效果
* Scroller.computeScrollOffset()方法是判断scroller的移动动画是否完成,当你调用startScroll()方法的时候这个方法返回的值一直都为true
* 如果采用其它方式移动视图比如:scrollTo()或 scrollBy时那么这个方法返回false
*/
@Override
public void computeScroll() {
super.computeScroll();
if(mScroller.computeScrollOffset()){
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}
}
XML中使用自定义控件
<me.zcy.androidheroes.MyScrollView
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/test1" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/test2" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/test3" />
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="fitXY"
android:src="@drawable/test4" />
</me.zcy.androidheroes.MyScrollView>
效果图

浙公网安备 33010602011771号