最近在做项目的时候遇到这么一个情况,如图1,上面有9块相同的小块绿地,它的下面是一大块地,如图2,如果不考虑屏幕适配的问题,要想实现这个非常的容易,但是如果考虑到屏幕适配,自定义viewgroup是一个解决方案。
图1 图2
下面是布局代码:
MyViewFeildGroup就是我自己定的一个集成viewgroup的布局方式。id为iv_big_field的图片大小决定MyViewFeildGroup的大小(因为布局的高宽都是wrap_content)。
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.swu.shen_pc.ninelayout.MainActivity">
<com.swu.shen_pc.ninelayout.nine_layout.MyViewFeildGroup
android:id="@+id/imageView"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<!--下面的最大块地-->
<ImageView
android:id="@+id/iv_big_field"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/farm_pic_land" />
<!--下面9个imageview分别是9块小绿地-->
<ImageView
android:id="@+id/iv_farm_green_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_5"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_6"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_7"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_8"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
<ImageView
android:id="@+id/iv_farm_green_9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:scaleType="fitXY"
android:src="@drawable/farm_pic_greenland"
android:visibility="visible" />
</com.swu.shen_pc.ninelayout.nine_layout.MyViewFeildGroup>
</RelativeLayout>
下面是MyViewGroup的Java代码:
onMearure方法用第一块大地的高宽计算出MyViewGroup布局的高宽,然后onLayout方法一次计算出这1块大地和其他9块小地相对于父布局的位置。
package com.swu.shen_pc.ninelayout.nine_layout;
import android.content.Context;
import android.util.AttributeSet;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import com.swu.shen_pc.ninelayout.BuildConfig;
/**
* Created by shen on 2015/12/22.
*/
public class MyViewFeildGroup extends ViewGroup {
private int mLandHeight;
private int mLandWidth;
public MyViewFeildGroup(Context context, AttributeSet attributes) {
super(context, attributes);
}
@Override
public LayoutParams generateLayoutParams(AttributeSet attrs) {
return new MarginLayoutParams(getContext(), attrs);
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int cCount = getChildCount();
double cWidth = 0;
double cHeight = 0;
MarginLayoutParams cParams = null;
/**
* 遍历所有childView根据其宽和高,以及margin进行布局
*/
for (int i = 0; i < cCount; i++) {
View childView = getChildAt(i);
cWidth = (1.0 / 3) * mLandWidth;
cHeight = (1.0 / 3) * mLandHeight;
double cl = 0.0, ct = 0.0, cr = 0.0, cb = 0.0;
switch (i) {
case 0:
cl = 0.0;
ct = 0.0;
cWidth = mLandWidth;
cHeight = mLandHeight;
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout((int) cl, (int) ct, (int) cr, (int) cb);
continue;
case 1:
cl = (1.0 / 3) * mLandWidth;
ct = 0.0;
break;
case 2:
cl = (1.0 / 6) * mLandWidth;
ct = (1.0 / 6) * mLandHeight;
break;
case 3:
cl = 0.0;
ct = (1.0 / 3) * mLandHeight;
break;
case 4:
cl = (1.0 / 2) * mLandWidth;
ct = (1.0 / 6) * mLandHeight;
break;
case 5:
cl = (1.0 / 3) * mLandWidth;
ct = (1.0 / 3) * mLandHeight;
break;
case 6:
cl = (1.0 / 6) * mLandWidth;
ct = (1.0 / 2) * mLandHeight;
break;
case 7:
cl = (2.0 / 3) * mLandWidth;
ct = (1.0 / 3) * mLandHeight;
break;
case 8:
cl = (1.0 / 2) * mLandWidth;
ct = (1.0 / 2) * mLandHeight;
break;
case 9:
cl = (1.0 / 3) * mLandWidth;
ct = (2.0 / 3) * mLandHeight;
break;
default:
break;
}
cr = cl + cWidth;
cb = cHeight + ct;
childView.layout((int) cl, (int) ct, (int) cr, (int) cb);
}
}
/**
* 计算所有ChildView的宽度和高度,如果高宽都是wrap_content,然后根据第一个childView的计算结果,设置自己的宽和高
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
/**
* 获得此ViewGroup上级容器为其推荐的宽和高,以及计算模式
*/
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int sizeWidth = MeasureSpec.getSize(widthMeasureSpec);
int sizeHeight = MeasureSpec.getSize(heightMeasureSpec);
// 计算出所有的childView的宽和高
measureChildren(widthMeasureSpec, heightMeasureSpec);
/**
* 记录如果是wrap_content是设置的宽和高
*/
int width;
int height;
int cWidth;
int cHeight;
MarginLayoutParams cParams = null;
/**
* 根据第1个childView,也就是第一块大地计算的出的宽和高,以及设置的margin计算容器的宽和高,主要用于容器是warp_content时
*/
View childView = getChildAt(0);
cWidth = childView.getMeasuredWidth();
cHeight = childView.getMeasuredHeight();
mLandHeight = childView.getMeasuredHeight();
mLandWidth = childView.getMeasuredWidth();
cParams = (MarginLayoutParams) childView.getLayoutParams();
width = cWidth + cParams.leftMargin + cParams.rightMargin;
height = cHeight + cParams.topMargin + cParams.bottomMargin;
if (BuildConfig.DEBUG) Log.d("MyViewFeildGroup", "height:" + height);
if (BuildConfig.DEBUG) Log.d("MyViewFeildGroup", "width:" + width);
/**
* 如果是wrap_content设置为我们计算的值
* 否则:直接设置为父容器计算的值
*/
setMeasuredDimension((widthMode == MeasureSpec.EXACTLY) ? sizeWidth
: width, (heightMode == MeasureSpec.EXACTLY) ? sizeHeight
: height);
}
}
好,到此为止自定义的MyViewFeildGroup就自定义完成了,在用eclipse或者Android studio预览布局的时候,可以选择多个分辨率的屏幕看看,当然其中还有很多细节没有处理,但是解决现在这个情况是绰绰有余了。