您的位置:首页 > 移动开发 > Android开发

Android之自定义ViewGroup

2016-09-20 21:47 369 查看
先来看一下下面的几个函数

<span style="font-family:Microsoft YaHei;font-size:18px;"> //获得WindowManager实例,主要用来管理窗口的一些状态、属性、view增加、删除、更新、窗口顺序、消息收集和处理等
WindowManager wm=(WindowManager)context.getSystemService(Context.WINDOW_SERVICE);
//获取手机分辨率类的实例对象
DisplayMetrics dm=new DisplayMetrics();
Log.i("info",dm.toString());
//将当前窗口的信息放到对象dm中
wm.getDefaultDisplay().getMetrics(dm);

Log.i("info",dm.toString());</span>

其中有两个Log,主要是用来见证wm.getDefaultDisplay().getMetrics(dm)的作用的
dm就是管理着手机界面的一些信息

第一个Log的信息如下:

DisplayMetrics{density=0.0, width=0, height=0, scaledDensity=0.0, xdpi=0.0, ydpi=0.0}

第二个Log的信息如下:

DisplayMetrics{density=2.0, width=720, height=1280, scaledDensity=2.0, xdpi=345.056, ydpi=342.231}

接着看一下将要自定义的ViewGroup的布局文件,也就是activity将要载入的

<com.example.administrator.viewgroupdemo.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" />

</com.example.administrator.viewgroupdemo.MyScrollView>

注意上面的每一个子ImageView的高度都是match_parent

下面是自定义ViewGroup部分

按照常规,对子视图进行布局,其中的onMeasure()并没有起到什么作用

/*
在调用onLayout的时候应该先调用onMeasure方法去测量子View
关于onLayout这个方法,只有是继承ViewGroup才要重载,要分配子view的位置
这个必须写,不然子视图将不会展示
*/
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int childCount=getChildCount();
//获取LayoutParams
MarginLayoutParams mlp=(MarginLayoutParams)getLayoutParams();
//指定LayoutParams的高度为子view高度之和
mlp.height=mScreenHeight*childCount;
//设置
setLayoutParams(mlp);
for(int i=0;i<childCount;i++){
View child=getChildAt(i);
if(child.getVisibility()!=View.GONE){
//为每一个子View布局
child.layout(l,i*mScreenHeight,r,(i+1)*mScreenHeight);
}
}
}

/**
* 当我删除这个函数的时候,并没有对整个视图造成影响
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@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);
}
}

布局建好后,下面是触摸事件
其中注释的结果是我一点一点试出来的,如果对getScrollY()不了解,理解代码会很繁琐的

@Override
public boolean onTouchEvent(MotionEvent event) {
int y=(int)event.getY();
switch(event.getAction()){
//触摸时操作
case MotionEvent.ACTION_DOWN:
mLastY=y;
//获得移动的Y的距离
mStart=getScrollY();
break;
//移动时操作
case MotionEvent.ACTION_MOVE:
//如果没有滚动完成,停止动画
if(!mScroller.isFinished()){
mScroller.abortAnimation();//停止动画
}
int dy=mLastY-y;
//这个if语句是判断是否到了顶部,如果是,则不移动
if(getScrollY()<0){
Log.i("info","顶部"+getScrollY());
dy=0;
}
//getHeight指的是整个自定义S从roller的高度,
//mScreenHeight是一个imageView的高度
//如果当前滑动的位置已经是最后一张图片了,停止移动
if(getScrollY()>getHeight()-mScreenHeight){
Log.i("info","底部"+getScrollY());
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;
}
//获取从接触开始到离开时的移动距离,有正负之分,lastNext就是为了获取向下滑动时相对于Scroller的距离
private int checkAlignment() {
int mEnd = getScrollY();
boolean isUp = ((mEnd - mStart) > 0) ? true : false;
//因为getScrollY()获取的值是针对整个Scroller的,而Scroller包含了几个ImageView
int lastPrev = mEnd % mScreenHeight;
int lastNext = mScreenHeight - lastPrev;
if (isUp) {
//向上的
return lastPrev;
} else {
return -lastNext;
}
}

/**
* 不太理解,但是删除该方法就会出问题
* 当startScroll执行过程中即在duration时间内,
* computeScrollOffset 方法会一直返回false,
* 但当动画执行完成后会返回返加true
*/
@Override
public void computeScroll() {
super.computeScroll();
if (mScroller.computeScrollOffset()) {
scrollTo(0, mScroller.getCurrY());
postInvalidate();
}
}

关于startScroll()函数,见http://ipjmc.iteye.com/blog/1615828
最后一个函数见http://blog.csdn.net/chenzhiqin20/article/details/8811428

就先说到这里
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: