先PO效果图
以上两种基本是比较常用的布局类型,以第一个图为例进行说明。
先看xml代码,凸显一下效率~~
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="@color/theme_white_color">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="200dp"
android:background="@mipmap/ic_top_nor"/>
<xxx.LineLinearLayout
android:id="@+id/line1"
app:line_image_right="@mipmap/ic_launcher"
app:line_title_text="巴拉巴拉巴拉"
style="@style/line_common"
/>
<xxx.LineLinearLayout
android:id="@+id/line2"
app:line_image_right="@mipmap/ic_launcher"
app:line_title_text="巴拉巴拉巴拉"
app:line_image_left="@mipmap/ic_back"
style="@style/line_common"
app:line_linepview_size_h="0dp"
/>
</LinearLayout>
</FrameLayout>
需要设置的三个参数:
app:line_image_right
app:line_title_text
app:line_image_left
以及一个style:
style="@style/line_common"
通过应用方式可以看出来,三个参数都是在attrs中设置的。
这种复用方式和<include layout="@layout/include_header_layout"/>
的区别在于,前者可以在一个页面中多样式复用,而后者只能同样式复用(View.GONE
等不计入为样式变更)。
实现
实现原理大概如下:
先定义一个布局原型,设置一下大概长什么样
比如第一个图 可以是这样:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:id="@+id/ll_line_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<ImageView
android:gravity="center_vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/iv_line_left" />
<TextView
android:gravity="center_vertical"
android:id="@+id/tv_line_title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<ImageView
android:gravity="center_vertical"
android:id="@+id/iv_line_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<View
android:id="@+id/v_line"
android:layout_width="10dp"
android:layout_height="10dp"/>
</LinearLayout>
里边有四个View:
- 靠左的图片
- 中间的文字
- 靠右的图片
- 下方的分割线
在attrs定义属性,大概包含了个控件的尺寸、内容、可设置的颜色、离上下左右的距离等,示例:
<!-- LineLinearLayout属性 -->
<declare-styleable name="LineLinearLayout">
<attr name="line_title_text" format="string" /> //标题文字内容
<attr name="line_title_text_size" format="dimension" /> //标题文字尺寸
<attr name="line_title_text_color" format="color" /> //标题文字颜色
<attr name="line_title_text_h" format="dimension"/> //标题文字高度
<attr name="line_image_left" format="reference" /> //图片资源
<attr name="line_image_left_width" format="dimension" /> //imageView的宽度
<attr name="line_image_left_height" format="dimension" /> //imageView的高度
<attr name="line_image_right" format="reference" /> //图片资源
<attr name="line_image_right_width" format="dimension" /> //imageView的宽度
<attr name="line_image_right_height" format="dimension" /> //imageView的高度
<attr name="line_linepview_size_w" format="dimension"/> //分割线的宽
<attr name="line_linepview_size_h" format="dimension"/> //分割线的高
<attr name="line_color" format="color" /> //背景色
</declare-styleable>
然后写个class,继承LinearLayout
,示例:
/**
* 描述:各页面条状布局···
* 创建者:uichi
* 创建时间:2019/1/14 16:26
* 建议所有margin值都列出来
*/
public class LineLinearLayout extends LinearLayout {
private ImageView leftImage;
private ImageView rightImage;
private TextView title;
private View lineview;
private LinearLayout linearLayout;
//显示内容
private String titleText;
private int titleTextColor;
private int titleTextSize;
private int titleTextH;
//左边图片
private Drawable drawableLeft;
private int drawableLeftw;
private int drawableLefth;
//右边图片
private Drawable drawableRight;
private int drawableRightw;
private int drawableRighth;
//底部分割线
private int lineHight;
private int lineWidth;
private int lineColor;
public LineLinearLayout(Context context) {
super(context);
}
public LineLinearLayout(Context context,@Nullable AttributeSet attrs) {
super(context, attrs);
if (!isInEditMode()) {
//解决可视化编辑器无法识别自定义控件的问题
// 在构造函数中将Xml中定义的布局解析出来。
LayoutInflater.from(context).inflate(R.layout.include_layout_linecard, this, true);
leftImage = findViewById(R.id.iv_line_left);
rightImage = findViewById(R.id.iv_line_right);
title = findViewById(R.id.tv_line_title);
linearLayout = findViewById(R.id.ll_line_layout);
lineview = findViewById(R.id.v_line);
}
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.LineLinearLayout);
titleText = a.getString(R.styleable.LineLinearLayout_line_title_text);
titleTextColor = a.getColor(R.styleable.LineLinearLayout_line_title_text_color, Color.WHITE);
titleTextSize = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_title_text_size, 12);
titleTextH = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_title_text_h, 60);
drawableLeftw = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_image_left_width, 0);
drawableLefth = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_image_left_height, 0);
drawableLeft = a.getDrawable(R.styleable.LineLinearLayout_line_image_left);
drawableRightw = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_image_right_width, 0);
drawableRighth = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_image_right_height, 0);
drawableRight = a.getDrawable(R.styleable.LineLinearLayout_line_image_right);
lineHight = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_linepview_size_h, 0);
lineWidth = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_linepview_size_w, 0);
lineColor = a.getColor(R.styleable.LineLinearLayout_line_color, 0xffffff);
if (!isInEditMode()) {
//将获取到的值设置到相应位置
LayoutParams linealayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, titleTextH);
linealayoutParams.setMargins(0, 0, 0, 0);
linearLayout.setBackgroundColor(lineColor);
linearLayout.setLayoutParams(linealayoutParams);
title.setText(titleText);
title.setTextSize(TypedValue.COMPLEX_UNIT_PX, titleTextSize);
title.setTextColor(titleTextColor);
LayoutParams layoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
layoutParams.setMargins(0, 0, 0, 0);
layoutParams.gravity = Gravity.CENTER;
title.setLayoutParams(layoutParams);
if(drawableLeft!=null){
leftImage.setImageDrawable(drawableLeft);
LayoutParams imageLeftLayoutParams = new LayoutParams(drawableLeftw, drawableLefth);
imageLeftLayoutParams.gravity = Gravity.CENTER;
imageLeftLayoutParams.setMargins(10, 0, 0, 0);
leftImage.setLayoutParams(imageLeftLayoutParams);
}else {
LayoutParams imageLeftLayoutParams = new LayoutParams(0, 0);
imageLeftLayoutParams.setMargins(0, 0, 0, 0);
leftImage.setLayoutParams(imageLeftLayoutParams);
}
rightImage.setImageDrawable(drawableRight);
LayoutParams imageRightLayoutParams = new LayoutParams(drawableRightw, drawableRighth);
imageRightLayoutParams.gravity = Gravity.CENTER;
imageRightLayoutParams.weight = 1;
imageRightLayoutParams.setMargins(0, 0, 10, 0);
rightImage.setLayoutParams(imageRightLayoutParams);
LayoutParams imageLineLayoutParams = new LayoutParams(lineWidth, lineHight);
//imageRightLayoutParams.gravity = Gravity.CENTER;
lineview.setBackgroundColor(lineColor);
lineview.setLayoutParams(imageLineLayoutParams);
}
a.recycle(); //这个别忘了
}
}
大概的意思是:
- 先把View读出来
- new一个TypedArray对象,用于读取attrs
- 利用attrs中的值对各个布局重设宽、高、居中、内容、颜色等属性
其中有一段:
if(drawableLeft!=null){
leftImage.setImageDrawable(drawableLeft);
LayoutParams imageLeftLayoutParams = new LayoutParams(drawableLeftw, drawableLefth);
imageLeftLayoutParams.gravity = Gravity.CENTER;
imageLeftLayoutParams.weight = 1;
imageLeftLayoutParams.setMargins(10, 0, 0, 0);
leftImage.setLayoutParams(imageLeftLayoutParams);
}else {
LayoutParams imageLeftLayoutParams = new LayoutParams(0, 0);
imageLeftLayoutParams.setMargins(0, 0, 0, 0);
leftImage.setLayoutParams(imageLeftLayoutParams);
}
drawableLeft在布局页面中有传入的话,就设置为(drawableLeftw, drawableLefth)
,没有传入就不占空间了,设置为(0, 0)
。
另外,从TypedArray中读取的数据,部分类型需要默认值,比如:
titleTextSize = a.getDimensionPixelOffset(R.styleable.LineLinearLayout_line_title_text_size, 12);
表示如果TextSize没有设置,那就默认为12。
接下来在xml布局文件中引用这个控件:
<你的路径.LineLinearLayout
android:id="@+id/line1"
app:line_image_right="@mipmap/ic_launcher"
app:line_title_text="巴拉巴拉巴拉"
······
/>
attrs中定义的属性基本都要赋值,但对同一个页面来说,基本的字号、背景色、尺寸等都是一致的,所以可以把attrs赋值写在style中。示例:
<style name="line_common">
<item name="line_image_left_height">20dp</item>
<item name="line_image_left_width">20dp</item>
<item name="line_color">@color/theme_white</item>
<item name="line_title_text_size">20dp</item>
<item name="line_title_text_color">@color/theme_blue_color</item>
<item name="line_title_text_h">60dp</item>
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="line_image_right_height">@dimen/margin_size50</item>
<item name="line_image_right_width">60dp</item>
<item name="line_linepview_size_w">10dp</item>
<item name="line_linepview_size_h">2dp</item>
</style>
然后在xml中引用,也可以在xml中重写,比如,第一图中,最后一行没有分割线,重写为:app:line_linepview_size_h="0dp"
<你的路径.LineLinearLayout
android:id="@+id/line2"
app:line_image_right="@mipmap/ic_launcher"
app:line_title_text="巴拉巴拉巴拉"
app:line_image_left="@mipmap/ic_back"
style="@style/line_common"
app:line_linepview_size_h="0dp"
/>
使用的方式还是比较多的,图中的设计样式是前边一截没有分割线,后边一截有分割线,不需要去画分割线,可以反过来将需要分割线的地方空出来。
如果是两边没分割线,中间有分割线呢?
这个时候需要在attrs中再添加两个属性:layout_marginRight
和layout_marginLeft
,示例:
//原有的
LayoutParams imageLineLayoutParams = new LayoutParams(lineWidth, lineHight);
//imageRightLayoutParams.gravity = Gravity.CENTER;
lineview.setBackgroundColor(lineColor);
lineview.setLayoutParams(imageLineLayoutParams);
//新的
LayoutParams imageLineLayoutParams = new LayoutParams(LayoutParams.MATCH_PARENT, lineHight);
imageLineLayoutParams.setMargins(marginLeft, 0, marginRight, 0);// 左、上、右、下
imageRightLayoutParams.gravity = Gravity.CENTER; //居中
lineview.setBackgroundColor(lineColor);
lineview.setLayoutParams(imageLineLayoutParams);
再在style中增加marginLeft、marginRight设置,xml中引用时,就已经变成了仅中间有分割线。
至此,就完事了。