本次主要是已知子视图的大小,父视图是未知的,父视图的大小随着所包裹内容的大小而变化
效果图如下
如图所示:父视图为绿色背景,小方块即子视图为蓝色背景,父视图所包裹的内容有多大,其大小就有多大,
子视图的多少是在layout-xml文件中改变的
在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.example.myviewgroup2.myViewGroup
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:background="@color/colorAccent">
<--子视图的添加,子视图的宽高均为150dp-->
<View
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginStart="25dp"
android:layout_marginTop="25dp"
android:background="@color/colorPrimaryDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginStart="25dp"
android:layout_marginTop="25dp"
android:background="@color/colorPrimaryDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginStart="25dp"
android:layout_marginTop="25dp"
android:background="@color/colorPrimaryDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="150dp"
android:layout_height="150dp"
android:layout_marginStart="25dp"
android:layout_marginTop="25dp"
android:background="@color/colorPrimaryDark"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</com.example.myviewgroup2.myViewGroup>
</androidx.constraintlayout.widget.ConstraintLayout>
自定义ViewGroup的步骤
1:自定义一个类继承与ViewGroup
class myViewGroup:ViewGroup {}
2:实现它的构造方法,这里只需要用到xml配置文件所以就只实现了xml的构造方法
//实现xml配置文件的构造函数
constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){}
3:实现必要的两个方法
(1):
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)}
在该方法中测量子视图的大小,以及确定父视图的大小,
(1.1):通过循环测量子视图的大小
//测量每一个孩子的大小
for (i in 0 until childCount){
val child = getChildAt(i)
measureChild(child,widthMeasureSpec,heightMeasureSpec)
}
(1.2):确定父视图的大小
//获取父容器的size与model
val parentHeightModel = MeasureSpec.getMode(heightMeasureSpec)
val parentWidthModel = MeasureSpec.getMode(widthMeasureSpec)
val parentHeightSize = MeasureSpec.getSize(heightMeasureSpec)
val parentWidthSize = MeasureSpec.getSize(widthMeasureSpec)
确定父容器的大小
//确定父容器的大小
for (i in 0 until childCount){
val child = getChildAt(i)
val lp = child.layoutParams
//确定容器的宽度
if (i == 0){
//是第一个
//父容器的宽度为装载一个子视图的容器
if (parentWidthModel == MeasureSpec.AT_MOST){
//父容器被设置为wrop_content时,为AT_MOST
//也就是父容器的大小是没有被确定的是需要自己确定的
parentWidth = lp.width + space
}else{
parentWidth = parentWidthSize
}
}else{
//后面的宽度一定
//只变化高度
if (parentWidthModel == MeasureSpec.AT_MOST){
parentWidth = (lp.width+space)*2}else{
parentWidth = parentWidthSize
}
}
//确定高度
if (i%2 == 0){
//进入到下一行了
if (parentHeightModel == MeasureSpec.AT_MOST){
parentHeight += lp.height+space
}else{
parentHeight = parentHeightSize
}
}
}
将父容器的大小记录下来
setMeasuredDimension(parentWidth,parentHeight)
(2):
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {}
在该方法中确切布局子视图,也就是将子视图布局到容器中的去
var top = space
var left = space
var bottom = 0
var right = 0
for (i in 0 until childCount){
val child = getChildAt(i)
val lp = child.layoutParams
bottom = top+lp.height
right = left + lp.width
if (i < 1){
child.layout(left,top,right,bottom)
left += (lp.width+space)
}else{
if (i%2 == 0){
//换行了
left = space
top += lp.height+space
bottom = top+lp.height
right = left + lp.width
child.layout(left,top,right,bottom)
left += lp.width+space
}else{
child.layout(left,top,right,bottom)
}
}
}
}
自定义viewGroup类的代码
package com.example.myviewgroup2
import android.content.Context
import android.util.AttributeSet
import android.util.Log
import android.view.ViewGroup
class myViewGroup:ViewGroup {
//子视图外间距
val space = 25
//实现xml配置文件的构造函数
constructor(context: Context,attributeSet: AttributeSet):super(context,attributeSet){}
//测量子控件的大小,和确定父控件的大小
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
//保存父容器的宽高 在没有内容时只有一个间隙
var parentHeight = space
var parentWidth = space
//获取父容器的size与model
val parentHeightModel = MeasureSpec.getMode(heightMeasureSpec)
val parentWidthModel = MeasureSpec.getMode(widthMeasureSpec)
val parentHeightSize = MeasureSpec.getSize(heightMeasureSpec)
val parentWidthSize = MeasureSpec.getSize(widthMeasureSpec)
//测量每一个孩子的大小
for (i in 0 until childCount){
val child = getChildAt(i)
measureChild(child,widthMeasureSpec,heightMeasureSpec)
}
//确定父容器的大小
for (i in 0 until childCount){
val child = getChildAt(i)
val lp = child.layoutParams
//确定容器的宽度
if (i == 0){
//是第一个
//父容器的宽度为装载一个子视图的容器
if (parentWidthModel == MeasureSpec.AT_MOST){
//父容器被设置为wrop_content时,为AT_MOST
//也就是父容器的大小是没有被确定的是需要自己确定的
parentWidth = lp.width + space
}else{
parentWidth = parentWidthSize
}
}else{
//后面的宽度一定
//只变化高度
if (parentWidthModel == MeasureSpec.AT_MOST){
parentWidth = (lp.width+space)*2}else{
parentWidth = parentWidthSize
}
}
//确定高度
if (i%2 == 0){
//进入到下一行了
if (parentHeightModel == MeasureSpec.AT_MOST){
parentHeight += lp.height+space
}else{
parentHeight = parentHeightSize
}
}
}
//记录父容器的大小
setMeasuredDimension(parentWidth,parentHeight)
}
override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
var top = space
var left = space
var bottom = 0
var right = 0
for (i in 0 until childCount){
val child = getChildAt(i)
val lp = child.layoutParams
bottom = top+lp.height
right = left + lp.width
if (i < 1){
child.layout(left,top,right,bottom)
left += (lp.width+space)
}else{
if (i%2 == 0){
//换行了
left = space
top += lp.height+space
bottom = top+lp.height
right = left + lp.width
child.layout(left,top,right,bottom)
left += lp.width+space
}else{
child.layout(left,top,right,bottom)
}
}
}
}
}