Android with a border of RelativeLayout, LinearLayout

Foreword

When developing, I will always encounter some dividing lines. I can use a View or an ImageView to draw a thin dividing line. I write a lot in the layout, it is very troublesome, and the code is not elegant, so a ViewGroup with a border. It will be a lot easier for development.

Realize

1, custom properties, written in the attr.xml file

<!--Border view, can be RelativeLayout or LinearLayout -->
<declare-styleable name="BorderViewLayout">
     <!--Border thickness -->
     <attr name="borderStrokeWidth" format="float"/>
     <!--Border color -->
     <attr name="borderColor" format="color"/>
     <!--The distance to the left of the bottom edge is broken -->
     <attr name="borderBottomLeftBreakSize" format="dimension"/>
     <!--The distance to the right of the bottom edge is broken -->
     <attr name="borderBottomRightBreakSize" format="dimension"/>
     <!--Do you need an upper border -->
     <attr name="needTopBorder" format="boolean"/>
     <!--Do you need left and right borders -->
     <attr name="needLeftAndRigtBorder" format="boolean"/>
     <!--Do you need a bottom border -->
     <attr name="needBottomBorder" format="boolean"/>
 </declare-styleable>

2, custom control, define a BorderRelativeLayout inherited from 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 or LinearLayout with border
 */
public class BorderRelativeLayout extends RelativeLayout {
    // default border width, 1dp
    public static final float DEFAULT_STROKE_WIDTH = 1.0f;

    //brush
    private Paint mPain;
    //Border color
    private int mPaintColor;
    / / border thickness
    private float mBorderStrokeWidth;
    //The distance to the left of the bottom edge is off
    private int mBorderBottomLeftBreakSize;
    //The distance to the right of the bottom edge is off
    private int mBorderBottomRightBreakSize;
    / / Do you need a border?
    private boolean isNeedTopBorder;
    / / Do you need left and right borders
    private boolean isNeedLeftAndRightBorder;
    / / Do you need a bottom border
    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);
        // Convert the DIP unit default to PXdisplayMetrics = context.getResources().getDisplayMetrics();// Get the custom attribute 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);
        //Set the brush to be non-aliasedmPain.setAntiAlias(true);
        //line widthmPain.setStrokeWidth(mBorderStrokeWidth);
    }@Override
    protected void dispatchDraw(Canvas canvas) {
        super.dispatchDraw(canvas);
        //Draw 4 sides
        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);
        }
    }

    /**
     * Set the border color
     *@paramcolor color
     */
    public void setBorderColor(int color){
        mPain.setColor(color);
        invalidate();
    }

    /**
     * Set the border width
     *@paramsize width
     */
    public void setBorderStrokeWidth(float size){
        mPain.setStrokeWidth(TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size, displayMetrics));
        invalidate();
    }

    /**
     * Set whether you need a top border
     *@paramneedtopborder boolean type
     */
    public void setNeedTopBorder(boolean needtopborder){
        isNeedTopBorder = needtopborder;
        invalidate();
    }

    /**
     * Set whether you need a bottom border
     *@paramneedbottomborder boolean type
     */
    public void setNeedBottomBorder(boolean needbottomborder){
        isNeedBottomBorder = needbottomborder;
        invalidate();
    }
}

3, use in the layout

<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">
        <!--First line -->
        <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="first row"
                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="First line of content"
                android:textSize="12sp"/>
        </com.junweiliu.widget.BorderRelativeLayout>
        <!--Second line -->
        <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="second line"
                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="Second line of content"
                android:textColor="#333333"
                android:textSize="12sp"/>
        </com.junweiliu.widget.BorderRelativeLayout>
    </LinearLayout>
</LinearLayout>

The effect is as follows:这里写图片描述

2. Use in ListView

1, BorderRelativeLayout with border can also be used in the ListView, such as the head with a dividing line

<?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"
        >
        <!--Top part-->
        <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="first row"
            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="First line of content"
            android:textSize="15sp"/>
        <!--Bottom part-->
        <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="second line"
            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="Second line of content"
            android:textSize="11sp"/>
    </com.junweiliu.widget.BorderRelativeLayout>

</LinearLayout>

You only need to make a judgment in the adapter to add a header split line. Add in the getView section of the adapter:

@Override
    public View getView(int position, View convertView, ViewGroup parent) {

        ...// If the first position shows the top border
        BorderRelativeLayout br = (BorderRelativeLayout) convertView.findViewById(R.id.br_ia_detail);if (0 == position) {
            br.setNeedTopBorder(true);
        } else {
            br.setNeedTopBorder(false);
        }
        return convertView;
    }

2, the split line in the ListView, you can also use this instead, just use it in the item layout.这里写图片描述

The use is relatively simple, the usage is also quite variable, if you need LinearLayout, just change the inheritance relationship.