1.ViewGroup
前面学习的安卓view说过,我认为安卓view就如word编辑当中的文字,图像,表格等等都是一个view.那么当我们的word文字,图像有规律的摆放组合起来形成一个比较好看的排版模式的时候,我们可以保存起来并且作为样式,那么以后每次编辑的时候只需要修改对应的文字内容以及图片内容就可以了。那么如此以来,viewgroup的概念也差不多了,我理解的viewgroup就是把一些view进行组合起来形成一个可以比较固定demo样式的view组合。它的作用就是作为各个view之间可以按一定规则摆放的组合demo样式供开发人员使用。套用模快速开发并且可以循环使用。

2.自定义view实例
既然说viewgroup是一些view组合样式,那么肯定有一些样式是没有的,那就需要我们自己创造,所以这就是自定义viewgroup了,自定义viewgroup可以让各个子view之间按我们的意愿摆放。
实现三个textview对角线摆放
(1)MyViewGroup文件
package com.gentle.viewgroup;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
public class MyViewGroup extends ViewGroup {
public MyViewGroup(Context context){
super(context);
}
public MyViewGroup(Context context, AttributeSet attrs){
super(context,attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int row = 0;
int column = 0;
int count = getChildCount();
for(int i=0;i<count;i++){
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
//子view的布局,即排放位置
child.layout(row,column,row+childWidth,column+childHeight);
row += childWidth;
column += childHeight;
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取viewgroup的测量方式以及大小
int groupWidthSize = MeasureSpec.getSize(widthMeasureSpec);
int groupHeightSize = MeasureSpec.getSize(heightMeasureSpec);
int groupWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int groupHeightMode = MeasureSpec.getMode(heightMeasureSpec);
//测量子view,下面要获取子view的宽度以及长度
measureChildren(widthMeasureSpec,heightMeasureSpec);
int widht = 0;
int height =0;
if(groupWidthMode == MeasureSpec.AT_MOST){
for (int i= 0; i < getChildCount();i++){
View child = getChildAt(i);//获取子view
widht += child.getMeasuredWidth();//获取子view大小
}
}else
widht = groupWidthSize;
if(groupHeightMode == MeasureSpec.AT_MOST){
for(int i=0;i<getChildCount();i++){
View child = getChildAt(i);
height += child.getMeasuredHeight();
}
}else
height = groupHeightSize;
setMeasuredDimension(widht,height);
}
}
(2)xml文件
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.gentle.viewgroup.MyViewGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorBack">
<TextView
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@color/colorRed"
android:padding="10dp"
android:text="hello"/>
<TextView
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorGreen"
android:padding="10dp"
android:text="world"/>
<TextView
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/colorBlue"
android:padding="10dp"
android:text="!"/>
</com.gentle.viewgroup.MyViewGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
(3)运行结果

3.添加viewgroup自定义属性以及子view间隔
主要是加入有子view的layout_position属性,就对layout_postion属性进行子view规则摆放,
layout_position为right的值的话,也就是枚举值为2,则子view就往右摆放,否则默认往左摆放。
(1)新建ViewGroup属性值,主要是枚举值
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="customLayoutPosition">
<attr name="layout_postion">
<enum name="left" value="1"/>
<enum name="right" value="2"/>
</attr>
</declare-styleable>
</resources>
(2)MyVierGroup
主要是以下几个重要点:
*重写generateLayoutParams方法,该方法主要放回一个继承MarginLayoutParams类型的对象,例如本例子中的MyLayoutParams,重写了该方法后就子view就可以通过child.getLayoutParams获取一个MarginLayoutParams类型对象。
*在测量onMeasure方法的时候把margin参数加上
*在onLayout中对子view进行间隔摆放处理
package com.gentle.viewgroup;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import com.gentle.gentleviewgroup.R;
import java.util.PropertyResourceBundle;
public class MyViewGroup extends ViewGroup {
public MyViewGroup(Context context){
super(context);
}
public MyViewGroup(Context context, AttributeSet attrs){
super(context,attrs);
}
//重写generateLayoutParams,主要获取子view相对于父控件的放置位置
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MyLayoutParams(getContext(),attrs);
}
//内部类继承MarginLayoutParams
public static class MyLayoutParams extends MarginLayoutParams {
private static final int POSITION_LEFT = 1;
private static final int POSITION_RIGHT = 2;
public int layout_position = 1;
public MyLayoutParams(Context context, AttributeSet attrs){
super(context,attrs);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.customLayoutPosition);
layout_position = typedArray.getInt(R.styleable.customLayoutPosition_layout_postion,0);
typedArray.recycle();
//默认从左边排列
if(layout_position == 0){
layout_position = 1;
}
}
public MyLayoutParams(int width, int height){
super(width,height);
}
public MyLayoutParams(LayoutParams source) {
super(source);
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//获取viewgroup的测量方式以及大小
int groupWidthSize = MeasureSpec.getSize(widthMeasureSpec);
int groupHeightSize = MeasureSpec.getSize(heightMeasureSpec);
int groupWidthMode = MeasureSpec.getMode(widthMeasureSpec);
int groupHeightMode = MeasureSpec.getMode(heightMeasureSpec);
//测量子view,下面要获取子view的宽度以及长度
measureChildren(widthMeasureSpec,heightMeasureSpec);
int widht = 0;
int height =0;
if(groupWidthMode == MeasureSpec.AT_MOST){
for (int i= 0; i < getChildCount();i++){
View child = getChildAt(i);//获取子view
MyLayoutParams layoutParams = (MyLayoutParams)child.getLayoutParams();
//考虑子view的间隔-----------------
widht += child.getMeasuredWidth()+layoutParams.leftMargin + layoutParams.rightMargin;//获取子view大小
}
}else
widht = groupWidthSize;
if(groupHeightMode == MeasureSpec.AT_MOST){
for(int i=0;i<getChildCount();i++){
View child = getChildAt(i);
MyLayoutParams layoutParams = (MyLayoutParams)child.getLayoutParams();
//考虑子view间隔
height += child.getMeasuredHeight() + layoutParams.topMargin + layoutParams.bottomMargin;
}
}else
height = groupHeightSize;
setMeasuredDimension(widht,height);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int row = 0;
int column = 0;
int count = getChildCount();
for(int i=0;i<count;i++){
View child = getChildAt(i);
int childWidth = child.getMeasuredWidth();
int childHeight = child.getMeasuredHeight();
//获取子view摆放规则
MyLayoutParams layoutParams = (MyLayoutParams) child.getLayoutParams();
//根据当前子view布局,依次靠右放置
if(layoutParams.layout_position == MyLayoutParams.POSITION_RIGHT){
child.layout(getWidth()-childWidth-layoutParams.rightMargin,column,getWidth()-layoutParams.rightMargin,column + childHeight);
}else {
//否则就默认从左斜线布局
//子view的布局,即排放位置
child.layout(row, column, row + childWidth, column + childHeight);
row += childWidth+layoutParams.leftMargin + layoutParams.rightMargin;
}
column += childHeight +layoutParams.topMargin + layoutParams.bottomMargin;
}
}
}
(3)xml布局文件
通过app:layout_postion = "right"往右摆放
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.gentle.viewgroup.MyViewGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@color/colorBack">
<TextView
android:layout_width="40dp"
android:layout_height="40dp"
android:background="@color/colorRed"
android:padding="10dp"
android:text="hello"
android:layout_margin="10dp"
app:layout_postion = "right"/>
<TextView
android:layout_width="60dp"
android:layout_height="60dp"
android:background="@color/colorGreen"
android:padding="10dp"
android:layout_margin="10dp"
android:text="world"
app:layout_postion = "right"/>
<TextView
android:layout_width="80dp"
android:layout_height="80dp"
android:background="@color/colorBlue"
android:padding="10dp"
android:layout_margin="10dp"
android:text="!"
app:layout_postion = "right"/>
</com.gentle.viewgroup.MyViewGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
(4)运行结果

本文深入探讨了安卓自定义ViewGroup的实现原理,包括如何创建自定义布局、添加自定义属性以及子view间隔处理,提供了具体实例代码和运行结果。
1067

被折叠的 条评论
为什么被折叠?



