自定义View(五)之继承ViewGroup
来源:互联网 发布:亿玛创新网络 编辑:程序博客网 时间:2024/06/05 14:23
一,概述
在android系统中可以把View分为两大类,一类是View,这类View本身具有展示UI的作用,比如TextView可以展示文本,ImageView可以展示图片,EditText可以编辑文字。另外一类是ViewGroup,即容器View,ViewGroup本质是容器,用来盛放View,并决定View的摆放位置,这类View如Linearlayout和RelativeLayout。
当我们需要一个容器来盛放现成的View,并需要View按照一定的要求摆放时我们需要继承ViewGroup。例如侧滑菜单,菜单部分和主页面部分都可以单独实现,但他们的摆放状态和滑动不能相互关联,此时就需要自定义容器View。下面就以侧滑菜单为例说明继承ViewGroup的自定义View的实现。
二,继承ViewGroup实现自定义View的步骤
直接上代码,注释写在代码中。
1,自定义一个类SlidingMenu,继承View,并重写构造方法
public class SlidingMenu extends ViewGroup { public SlidingMenu(Context context) { super(context); } public SlidingMenu(Context context, AttributeSet attrs) { super(context, attrs); } public SlidingMenu(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { }}
注意事项:
1,由于ViewGroup的onLayout方法是抽象方法,所以必须重写。onLayout方法很重要,它决定子view的摆放位置,要着重注意。
2,重写三个构造方法。这三个构造方法的作用及使用场合与继承View时的三个构造方法完全相同。
2,在布局文件中使用SlidingMenu
因为SlidingMenu是容器View,与Linearlayout同一类型,所以用法也类似于Linearlayout,在SlidingMenu中写上子View,如下:
<honor.com.slidingmenu.view.SlidingMenu android:layout_width="match_parent" android:layout_height="match_parent"> <!--菜单页面的View--> <TextView android:id="@+id/menu_page" android:layout_width="240dp" android:layout_height="match_parent" android:text="菜单" android:background="#f00" android:textSize="30sp" android:textColor="#000"/> <!--主页面的View--> <TextView android:id="@+id/main_page" android:layout_width="240dp" android:layout_height="match_parent" android:text="主页面" android:background="#ff0" android:textSize="30sp" android:textColor="#000"/></honor.com.slidingmenu.view.SlidingMenu>
注意事项:
1,由于容器View一般不会单独使用,所以在使用ViewGroup自定义容器View时要结合View一块使用。
2,此时SlidingMenu是容器View,里面可以放任意类型的View,包括Linearlayout或RelativeLayout等容器View。这儿放了两个TextView是为了简化代码,便于说明问题。
3,菜单View高度充满全屏,宽度为240dp,背景颜色设为红色,便于与主页面区分。
4,主页面View高度和宽度都充满屏幕,正常显示时只显示主页面,滑动时才会显示出菜单页面。
3,重写SlidingMenu的onFinishInflate方法,在这个方法中获取menuView和mainView
这一步的作用是获取menuView和mainView。代码如下:
protected void onFinishInflate() { super.onFinishInflate(); menuView = getChildAt(0); mainView = getChildAt(1); }
说明:
1,onFinishInflate是当解析布局文件完成,并生成View对象后调用的方法,此时可以通过getChildAt方法得到对应的子View。
2,getchildAt方法是根据索引获取子View对象,这个索引对应布局文件中的顺序,所以索引为0就是菜单View,索引为1就是主页面View。
3,getChildAt方法不能在构造方法中使用,因为构造方法执行时只是创建了SlidingMenu对象,并没有把子View对象放入到容器中,所以必须在布局文件解析完成后才能使用。当然在onMeasure方法和onLayout方法中都可以使用。
4,重写onMeasure方法
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //从布局文件中得到菜单view的宽度 menuViewWidth = menuView.getLayoutParams().width; //指定menuView的宽度测量模式为MeasureSpec.EXACTLY int menuViewWidthMeasereMode = MeasureSpec.EXACTLY; //根据宽度和测量模式得到宽度测量规则 int menuWidthMeasureSpec = MeasureSpec.makeMeasureSpec(menuViewWidth, menuViewWidthMeasereMode); //测量menuView menuView.measure(menuWidthMeasureSpec, heightMeasureSpec); // 测量mainView mainView.measure(widthMeasureSpec, heightMeasureSpec);}
说明:
1,这个方法中做了两件事,一是调用super.onMeasure方法测量自己。二是调用子view的measure方法测量子View。
2,由于在布局文件中给SlidingMenu设置的宽高都是match_parent,所以onMeasure方法传递过来的测量规则都是充满屏幕,所以对于测量自己可以直接把这两个参数传递进去。
3,我们希望显示的menuView的宽是240dp,所以这个宽度测量规则要根据布局文件中设置的宽度生成测量规则。对于menuView的高希望是充满屏幕,此时直接使用了sliddingMenu的高度测量规则,当然我们也可以获取menuView在布局文件中设置的高度,但效果是一样的,所以直接使用了slidingMenu的高度测量规则。
4,对于mainView,我们希望高宽都充满屏幕,所以高宽都直接使用SlidingMenu的高宽测量规则。
5,重写onLayout方法
protected void onLayout(boolean changed, int l, int t, int r, int b) { menuViewLeft = l - menuViewWidth;//得到menuView的左侧坐标 int menuViewRight = menuViewLeft + menuViewWidth;//得到menuView的右侧坐标 menuView.layout(menuViewLeft,t,menuViewRight,b);//设置menuView的上、下、左、右四个坐标。 int mainViewLeft = menuViewRight;//得到menuView的左侧坐标 int mainViewRight = menuViewRight + r;//得到menuView的右侧坐标 mainView.layout(mainViewLeft,t,mainViewRight,b);//设置menuView的上、下、左、右四个坐标。 }
说明:
1,onLayout方法的作用是布局子View,自己的布局不在onLayout方法中。
2,布局子view即调用子View的layout方法,传递进入上、下、左、右四个坐标。
3,onLayout方法传递过来四个int类型的值,分别是SlidingMenu的上下左右坐标,由于slidingMenu是充满屏幕的,所以SlidingMenu的上下左右坐标分别对应屏幕的上下左右坐标。
4,menuView在默认状态下的右侧坐标在屏幕的左侧,所以左侧坐标就是l - menuViewWidth.
5,mainView在默认状态下是全屏显示。但是侧滑菜单时需要滑动的,所以不能直接使用SlidingMenu的上下左右坐标。mainView要随menuView的位置改变而改变,所以mainView的左侧坐标应该等于menuView的右侧坐标。
截止到此处,基本功能已经完成,可以运行了。但是运行结果只能显示出mainView,而看不到menuView。因为menuView在屏幕的左侧,只有滑动时才能显示出来。下面写滑动的逻辑。
6,重写onTouchEvent实现菜单滑动
public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: downX = event.getX();//记录按下的位置 break; case MotionEvent.ACTION_MOVE: distanceX = (int) (event.getX()-downX+ oldDistanceX);//得到滑动的距离 if(distanceX < 0){//为了避免右侧滑出边界 distanceX=0; }else if(distanceX > menuViewWidth){//为了避免右侧滑出边界 distanceX = menuViewWidth; } scrollXTo(distanceX);//滑动view break; case MotionEvent.ACTION_UP: if(distanceX < menuViewWidth/2){//当手指抬起时偏向于主页面,就退出菜单 distanceX=0; }else { distanceX = menuViewWidth;//否则就完全滑出菜单 } scrollXTo(distanceX);//滑动View oldDistanceX = distanceX; break; } return true; } /** * 封装view的scrollTo方法。 */ private void scrollXTo(float x){ scrollTo((int) -x,0); }
此时即可滑动菜单了。
- 自定义View(五)之继承ViewGroup
- 自定义View学习笔记之继承ViewGroup
- 自定义View继承ViewGroup
- 自定义View继承ViewGroup
- 自定义view继承viewgroup的解释
- Android自定义View(四)继承ViewGroup
- 自定义view继承viewgroup,实现组合按钮。
- Android 自定义view(三) 继承ViewGroup
- 自定义View---继承ViewGroup动效
- 了解自定义View和继承View,继承ViewGroup,继承已有View,继承已有ViewGroup实例ji
- Android进阶——自定义View之继承ViewGroup实现自己的ScrollView
- Android自定义控件-完全自定义(继承View ,ViewGroup)
- 自定义view 之 继承
- 自定义view之继承view
- 自定义View之 继承View
- android 自定义 view 之ViewGroup(四)
- Android继承自View和ViewGroup,自定义控件
- android 自定义View学习总结-继承自ViewGroup
- To Determine a Prime Number
- Flink JOIN 执行计划
- GO语言最右边斜打印二维数组
- Linux下编译安装boost
- 四、vault
- 自定义View(五)之继承ViewGroup
- 【PostgreSQL-9.6.3】数据表操作语句
- (个人)AR电子书系统创新实训第三周(1)
- JavaWeb三大组件之一Servlet【Servlet接口】
- 五、vault
- MySql表结构修改
- L1,L2
- 创建型模式之单例模式
- eclipse中clean的作用