前言
开发的时候总会遇到一些分割线,可以用一个View或者一个ImageView来绘制一条比较细的分割线,但布局写多了,感觉很麻烦,而且显得代码不优雅,所以一个带有边框的ViewGroup对开发会方便很多。
1. 实现
1、自定义属性,在 attr.xml 文件中写入
<!--边框的view,可以是 RelativeLayout 或 LinearLayout -->
<declare-styleable name="BorderViewLayout">
<!--边框的粗度-->
<attr name="borderStrokeWidth" format="float"/>
<!--边框颜色-->
<attr name="borderColor" format="color"/>
<!--底边边线左边断开距离-->
<attr name="borderBottomLeftBreakSize" format="dimension"/>
<!--底边边线右边断开距离-->
<attr name="borderBottomRightBreakSize" format="dimension"/>
<!--是否需要上边框-->
<attr name="needTopBorder" format="boolean"/>
<!--是否需要左右边框-->
<attr name="needLeftAndRigtBorder" format="boolean"/>
<!--是否需要下边框-->
<attr name="needBottomBorder" format="boolean"/>
</declare-styleable>
2、自定义控件,定义一个 BorderRelativeLayout 继承自 RelativeLayout
package com.tcmain.djim.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.util.TypedValue;
import android.widget.RelativeLayout;
import com.risen.tclibrary.R;
/**
* Created by sgll on 2018/7/17.
* 带边框的RelativeLayout 或 LinearLayout
*/
public class BorderRelativeLayout extends RelativeLayout {
// 默认边框宽度, 1dp
public static final float DEFAULT_STROKE_WIDTH = 1.0f;
//画笔
private Paint mPain;
//边框颜色
private int mPaintColor;
//边框粗细
private float mBorderStrokeWidth;
//底边边线左边断开距离
private int mBorderBottomLeftBreakSize;
//底边边线右边断开距离
private int mBorderBottomRightBreakSize;
//是否需要上边框
private boolean isNeedTopBorder;
//是否需要左右边框
private boolean isNeedLeftAndRightBorder;
//是否需要下边框
private boolean isNeedBottomBorder;
private DisplayMetrics displayMetrics;
public BorderRelativeLayout(Context context) {
this(context, null);
}
public BorderRelativeLayout(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public BorderRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 将DIP单位默认值转为PX
displayMetrics = context.getResources().getDisplayMetrics();
// 获取自定义属性
TypedArray ta = context.obtainStyledAttributes(attrs, R.styleable.BorderViewLayout);
mPaintColor = ta.getColor(R.styleable.BorderViewLayout_borderColor, Color.GRAY);
mBorderStrokeWidth = ta.getFloat(R.styleable.BorderViewLayout_borderStrokeWidth, DEFAULT_STROKE_WIDTH);
// mBorderStrokeWidth = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mBorderStrokeWidth, displayMetrics);
mBorderBottomLeftBreakSize = ta.getDimensionPixelSize(R.styleable.BorderViewLayout_borderBottomLeftBreakSize, 0);
mBorderBottomLeftBreakSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mBorderBottomLeftBreakSize, displayMetrics);
mBorderBottomRightBreakSize = ta.getDimensionPixelSize(R.styleable.BorderViewLayout_borderBottomRightBreakSize, 0);
mBorderBottomRightBreakSize = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, mBorderBottomRightBreakSize, displayMetrics);
isNeedTopBorder = ta.getBoolean(R.styleable.BorderViewLayout_needTopBorder, true);
isNeedLeftAndRightBorder = ta.getBoolean(R.styleable.BorderViewLayout_needLeftAndRigtBorder, false);
isNeedBottomBorder = ta.getBoolean(R.styleable.BorderViewLayout_needBottomBorder, true);
ta.recycle();
init();
}
private void init(){
mPain = new Paint();
mPain.setColor(mPaintColor);
//设置画笔为无锯齿
mPain.setAntiAlias(true);
//线宽
mPain.setStrokeWidth(mBorderStrokeWidth);
}
@Override
protected void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
//画4个边
if(isNeedTopBorder){
canvas.drawLine(0, 0, this.getWidth(), 0, mPain);
}
if(isNeedBottomBorder){
canvas.drawLine(mBorderBottomLeftBreakSize, this.getHeight(), this.getWidth() - mBorderBottomRightBreakSize, this.getHeight(), mPain);
}
if(isNeedLeftAndRightBorder){
canvas.drawLine(0, 0, 0, this.getHeight(), mPain);
canvas.drawLine(this.getWidth(), 0, this.getWidth(), this.getHeight(), mPain);
}
}
/**
* 设置边框颜色
* @param color 颜色
*/
public void setBorderColor(int color){
mPain.setColor(color);
invalidate();
}
/**
* 设置边框宽度
* @param size 宽度
*/
public void setBorderStrokeWidth(float size){
mPain.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, displayMetrics));
invalidate();
}
/**
* 设置是否需要顶部边框
* @param needtopborder boolean类型
*/
public void setNeedTopBorder(boolean needtopborder){
isNeedTopBorder = needtopborder;
invalidate();
}
/**
* 设置是否需要底部边框
* @param needbottomborder boolean类型
*/
public void setNeedBottomBorder(boolean needbottomborder){
isNeedBottomBorder = needbottomborder;
invalidate();
}
}
3、在布局中使用
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:br="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<!--第一行-->
<com.junweiliu.widget.BorderRelativeLayout
android:layout_width="match_parent"
android:layout_height="68dp"
android:gravity="center_vertical"
br:borderBottomLeftBreakSize="16dp"
br:borderBottomRightBreakSize="16dp"
br:borderColor="#eeeeee"
br:borderStrokeWidth="3.0">
<TextView
android:id="@+id/tv_balance_txt"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:gravity="center"
android:text="第一行"
android:textSize="15sp"/>
<ImageView
android:id="@+id/iv_ia_prompt"
android:layout_width="14dp"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:layout_toRightOf="@+id/tv_balance_txt"
android:src="@mipmap/ic_launcher"/>
<TextView
android:id="@+id/tv_balance_number"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:layout_marginTop="24dp"
android:textColor="#333333"
android:text="第一行内容"
android:textSize="12sp"/>
</com.junweiliu.widget.BorderRelativeLayout>
<!--第二行-->
<com.junweiliu.widget.BorderRelativeLayout
android:layout_width="match_parent"
android:layout_height="67dp"
android:gravity="center_vertical"
br:borderColor="#eeeeee"
br:borderStrokeWidth="3.0"
br:needTopBorder="false">
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginLeft="16dp"
android:gravity="center"
android:text="第二行"
android:textSize="15sp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentRight="true"
android:layout_marginRight="16dp"
android:gravity="center"
android:text="第二行内容"
android:textColor="#333333"
android:textSize="12sp"/>
</com.junweiliu.widget.BorderRelativeLayout>
</LinearLayout>
</LinearLayout>
效果如下:
2. 在ListView中使用
1、带边框的 BorderRelativeLayout 也可使用 ListView 中,如头部带分割线
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:br="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/white"
android:orientation="vertical">
<com.junweiliu.widget.BorderRelativeLayout
android:id="@+id/br_ia_detail"
android:layout_width="match_parent"
android:layout_height="72dp"
br:borderColor="#333333"
br:borderStrokeWidth="2.0"
br:needTopBorder="false"
>
<!--上边部分-->
<TextView
android:id="@+id/tv_ia_detail_name"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="16sp"
android:layout_marginTop="15dp"
android:text="第一行"
android:textSize="15sp" />
<TextView
android:id="@+id/tv_ia_detail_money"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="15dp"
android:layout_marginTop="15dp"
android:text="第一行内容"
android:textSize="15sp"/>
<!--下边部分-->
<TextView
android:id="@+id/tv_ia_detail_balance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:layout_marginBottom="15dp"
android:layout_marginLeft="16dp"
android:layout_marginTop="12dp"
android:text="第二行"
android:textSize="11sp"/>
<TextView
android:id="@+id/tv_ia_detail_date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:layout_marginBottom="15dp"
android:layout_marginRight="15dp"
android:layout_marginTop="12dp"
android:text="第二行内容"
android:textSize="11sp"/>
</com.junweiliu.widget.BorderRelativeLayout>
</LinearLayout>
只需要在适配器中进行判断,就能够添加头部分割线了。在适配器getView部分添加:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
...
// 如果是第一个位置显示顶部边框
BorderRelativeLayout br = (BorderRelativeLayout) convertView.findViewById(R.id.br_ia_detail);
if (0 == position) {
br.setNeedTopBorder(true);
} else {
br.setNeedTopBorder(false);
}
return convertView;
}
2、ListView 中的分割线,也可使用这个代替,只需在 item 布局里使用即可。
3. 总结
使用比较简单,用法也比较多变,如果需要 LinearLayout,只需改变一下继承关系就可以了。