国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

談?wù)凙ndroid中的Divider是個什么東東

2020-01-02 07:02:11
字體:
供稿:網(wǎng)友

在Android應(yīng)用開發(fā)中會經(jīng)常碰到一個叫divider的東西,就是兩個View之間的分割線。最近工作中注意到這個divider并分析了一下,竟然發(fā)現(xiàn)內(nèi)有乾坤,驚為天人…

ListView的divider

1. 定制divider的邊距

ListView的divider默認是左右兩頭到底的,如何簡單的設(shè)置一個邊距呢?

利用inset或者layer-list都可以簡單的實現(xiàn),代碼如下:

<!-- 方法一 --><?xml version="1.0" encoding="utf-8"?><inset xmlns:android="http://schemas.android.com/apk/res/android"android:insetLeft="16dp" ><shape android:shape="rectangle" ><solid android:color="#f00" /></shape></inset><!-- 方法二 --><?xml version="1.0" encoding="utf-8"?><layer-list xmlns:android="http://schemas.android.com/apk/res/android"><item android:left="16dp"><shape android:shape="rectangle"><solid android:color="#f00" /></shape></item></layer-list>

其中inset除了左邊距insetLeft, 還有insetTop、insetRight、insetBottom, 效果圖:

2. 最后一項的divider

很多同學(xué)可能發(fā)現(xiàn)了,ListView最后一項的divider有時候有,有時候又沒有。

我畫個圖大家就都能理解了:

 

上面是數(shù)據(jù)不足的顯示效果,如果數(shù)據(jù)滿屏的話,都是看不多最后的divider的。

真相是,當(dāng)ListView高度是不算最后一項divider的,所以只有在match_parent的情況下,ListView的高度是有余的,才能畫出最后的那個divider。

ps:網(wǎng)上很多資料,把最后一項的divider和footerDividersEnabled混在一起了,這個是不對的,兩個從邏輯上是獨立的,類似的還有一個headerDividersEnabled,headerDividersEnabled和footerDividersEnabled不會影響到默認情況下最后的divider的繪制,他們是給header和footer專用的,特此說明。

RecyclerView的Divider

RecyclerView的Divider叫做ItemDecoration,RecyclerView.ItemDecoration本身是一個抽象類,官方?jīng)]有提供默認實現(xiàn)。

官方的Support7Demos例子中有個DividerItemDecoration, 我們可以直接參考一下,位置在sdk的這里:

extras/android/support/samples/Support7Demos/src/…/…/decorator/DividerItemDecoration.java

但是這個DividerItemDecoration有三個問題:

只支持系統(tǒng)默認樣式,不支持自定義Drawable類型的divider

里面的算法對于無高寬的Drawable(比如上面用到的InsetDrawable)是畫不出東西的水平列表的Divider繪制方法drawHorizontal()的right計算有誤,導(dǎo)致垂直Divider會繪制不出來,應(yīng)該改為:final int right = left + mDivider.getIntrinsicWidth();;

針對這幾個問題,我修復(fù)并增強了一下:

import android.content.Context;import android.content.res.TypedArray;import android.graphics.Canvas;import android.graphics.Rect;import android.graphics.drawable.Drawable;import android.support.v4.view.ViewCompat;import android.support.v7.widget.LinearLayoutManager;import android.support.v7.widget.RecyclerView;import android.view.View;/*** RecyclerView的ItemDecoration的默認實現(xiàn)* 1. 默認使用系統(tǒng)的分割線* 2. 支持自定義Drawable類型* 3. 支持水平和垂直方向* 4. 修復(fù)了官方垂直Divider顯示的bug* 擴展自官方android sdk下的Support7Demos下的DividerItemDecoration*/public class DividerItemDecoration extends RecyclerView.ItemDecoration {private static final int[] ATTRS = new int[]{android.R.attr.listDivider};public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;private Drawable mDivider;private int mWidth;private int mHeight;private int mOrientation;public DividerItemDecoration(Context context, int orientation) {final TypedArray a = context.obtainStyledAttributes(ATTRS);mDivider = a.getDrawable(0);a.recycle();setOrientation(orientation);}/*** 新增:支持自定義dividerDrawable** @param context* @param orientation* @param dividerDrawable*/public DividerItemDecoration(Context context, int orientation, Drawable dividerDrawable) {mDivider = dividerDrawable;setOrientation(orientation);}public void setOrientation(int orientation) {if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {throw new IllegalArgumentException("invalid orientation");}mOrientation = orientation;}/*** 新增:支持手動為無高寬的drawable制定寬度* @param width*/public void setWidth(int width) {this.mWidth = width;}/*** 新增:支持手動為無高寬的drawable制定高度* @param height*/public void setHeight(int height) {this.mHeight = height;}@Overridepublic void onDraw(Canvas c, RecyclerView parent) {if (mOrientation == VERTICAL_LIST) {drawVertical(c, parent);} else {drawHorizontal(c, parent);}}public void drawVertical(Canvas c, RecyclerView parent) {final int left = parent.getPaddingLeft();final int right = parent.getWidth() - parent.getPaddingRight();final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {final View child = parent.getChildAt(i);final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();final int top = child.getBottom() + params.bottomMargin +Math.round(ViewCompat.getTranslationY(child));final int bottom = top + getDividerHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}public void drawHorizontal(Canvas c, RecyclerView parent) {final int top = parent.getPaddingTop();final int bottom = parent.getHeight() - parent.getPaddingBottom();final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {final View child = parent.getChildAt(i);final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();final int left = child.getRight() + params.rightMargin +Math.round(ViewCompat.getTranslationX(child));final int right = left + getDividerWidth();mDivider.setBounds(left, top, right, bottom);mDivider.draw(c);}}@Overridepublic void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {if (mOrientation == VERTICAL_LIST) {outRect.set(0, 0, 0, getDividerHeight());} else {outRect.set(0, 0, getDividerWidth(), 0);}}private int getDividerWidth() {return mWidth > 0 ? mWidth : mDivider.getIntrinsicWidth();}private int getDividerHeight() {return mHeight > 0 ? mHeight : mDivider.getIntrinsicHeight();}}

使用如下:

// 默認系統(tǒng)的dividerdividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST);// 自定義圖片drawable分的dividerdividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST, getResources().getDrawable(R.drawable.ic_launcher));// 自定義無高寬的drawable的divider - 垂直列表dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.VERTICAL_LIST, new ColorDrawable(Color.parseColor("#ff00ff")));dividerItemDecoration.setHeight(1);// 自定義無高寬的drawable的divider - 水平列表dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL_LIST, new ColorDrawable(Color.parseColor("#ff00ff")));dividerItemDecoration.setWidth(1);// 自定義帶邊距且無高寬的drawable的divider(以上面InsetDrawable為例子)// 這個地方也可以在drawable的xml文件設(shè)置size指定寬高,效果一樣dividerItemDecoration = new DividerItemDecoration(this, DividerItemDecoration.HORIZONTAL_LIST, getResources().getDrawable(R.drawable.list_divider));dividerItemDecoration.setWidth(DisplayLess.$dp2px(16) + 1);

手動的Divider

有的時候沒有系統(tǒng)控件的原生支持,只能手動在兩個view加一個divider,比如,設(shè)置界面每項之間的divider,水平平均分隔的幾個view之間加一個豎的divider等等。

無論橫的豎的,都非常簡單,定一個View,設(shè)置一個background就可以了,正常情況下沒什么好說的。

下面我們來考慮一種常見設(shè)置界面,這種設(shè)置界面的分割線是有左邊距的,比如微信的設(shè)置界面,我相信絕大部分人的布局代碼都是這樣實現(xiàn)的:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><!--這個group_container的background一定要設(shè)置,而且要和list_item_bg的list_item_normal一致,否則效果會不正確。 --><LinearLayoutandroid:id="@+id/group_container"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_marginTop="48dp"android:background="#fff"android:orientation="vertical"><RelativeLayoutandroid:id="@+id/account_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/list_item_bg"android:clickable="true"><TextViewandroid:id="@+id/account_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:layout_margin="16dp"android:text="First Item"android:textColor="#f00"android:textSize="16sp" /></RelativeLayout><Viewandroid:layout_width="match_parent"android:layout_height="1px"android:layout_marginLeft="16dp"android:background="#f00" /><RelativeLayoutandroid:id="@+id/phone_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/list_item_bg"android:clickable="true"><TextViewandroid:id="@+id/phone_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:layout_margin="16dp"android:text="Second Item"android:textColor="#f00"android:textSize="16sp" /></RelativeLayout></LinearLayout></RelativeLayout>

效果圖如下,順便我們也看看它的Overdraw狀態(tài):

 

通過分析Overdraw的層次,我們發(fā)現(xiàn)為了一個小小的邊距,設(shè)置了整個groud_container的背景,從而導(dǎo)致了一次Overdraw。

能不能優(yōu)化掉這個Overdraw?答案是肯定的。

背景肯定要去掉,但是這個左邊距的View就不能這么簡單的寫了,需要自定義一個View,它要支持能把左邊距的空出的16dp的線用list_item_normal的顏色值繪制一遍,這樣才能看的出左邊距。

這個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.TypedValue;import android.view.View;import com.jayfeng.lesscode.core.R;public class SpaceDividerView extends View {private int mSpaceLeft = 0;private int mSpaceTop = 0;private int mSpaceRight = 0;private int mSpaceBottom = 0;private int mSpaceColor = Color.TRANSPARENT;private Paint mPaint = new Paint();public SpaceDividerView(Context context) {this(context, null);}public SpaceDividerView(Context context, AttributeSet attrs) {this(context, attrs, 0);}public SpaceDividerView(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SpaceDividerView, defStyleAttr, 0);mSpaceLeft = a.getDimensionPixelSize(R.styleable.SpaceDividerView_spaceLeft,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics()));mSpaceTop = a.getDimensionPixelSize(R.styleable.SpaceDividerView_spaceTop,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics()));mSpaceRight = a.getDimensionPixelSize(R.styleable.SpaceDividerView_spaceRight,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics()));mSpaceBottom = a.getDimensionPixelSize(R.styleable.SpaceDividerView_spaceBottom,(int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 0, getResources().getDisplayMetrics()));mSpaceColor = a.getColor(R.styleable.SpaceDividerView_spaceColor, Color.TRANSPARENT);a.recycle();mPaint.setColor(mSpaceColor);}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);if (mSpaceLeft > 0) {canvas.drawRect(0, 0, mSpaceLeft, getMeasuredHeight(), mPaint);}if (mSpaceTop > 0) {canvas.drawRect(0, 0, getMeasuredWidth(), mSpaceTop, mPaint);}if (mSpaceRight > 0) {canvas.drawRect(getMeasuredWidth() - mSpaceRight, 0, getMeasuredWidth(), getMeasuredHeight(), mPaint);}if (mSpaceBottom > 0) {canvas.drawRect(0, getMeasuredHeight() - mSpaceBottom, getMeasuredWidth(), getMeasuredHeight(), mPaint);}}}

用這個SpaceDividerView我們重寫一下上面的布局代碼:

<RelativeLayout 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"><LinearLayoutandroid:id="@+id/group_container"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentTop="true"android:layout_marginTop="48dp"android:orientation="vertical"><RelativeLayoutandroid:id="@+id/account_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/list_item_bg"android:clickable="true"><TextViewandroid:id="@+id/account_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:layout_margin="16dp"android:text="First Item"android:textColor="#f00"android:textSize="16sp" /></RelativeLayout><com.jayfeng.lesscode.core.other.SpaceDividerViewandroid:layout_width="match_parent"android:layout_height="1px"android:background="#f00"app:spaceLeft="16dp"app:spaceColor="@color/list_item_normal"/><RelativeLayoutandroid:id="@+id/phone_container"android:layout_width="match_parent"android:layout_height="wrap_content"android:background="@drawable/list_item_bg"android:clickable="true"><TextViewandroid:id="@+id/phone_title"android:layout_width="wrap_content"android:layout_height="wrap_content"android:layout_alignParentLeft="true"android:layout_centerVertical="true"android:layout_margin="16dp"android:text="Second Item"android:textColor="#f00"android:textSize="16sp" /></RelativeLayout></LinearLayout></RelativeLayout>

效果圖和Overdraw狀態(tài)如下:

 

界面中g(shù)roup_container那塊由之前的綠色變成了藍色,說明減少了一次Overdraw。

上述情況下,SpaceDividerView解耦了背景色,優(yōu)化了Overdraw,而且這個SpaceDividerView也是支持4個方向的,使用起來特別方便。

陰影divider

陰影分割線的特點是重疊在下面的view之上的,它的目的是一種分割線的立體效果。

 

使用RelativeLayout并控制上邊距離可以實現(xiàn):

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"><!-- layout_marginTop的值應(yīng)該就是不包括陰影高度的header高度--><LinearLayoutandroid:layout_width="match_parent"android:layout_height="match_parent"android:layout_alignParentTop="true"android:layout_marginTop="@dimen/header_height"android:orientation="vertical"></LinearLayout><!-- 這個要放在最后,才能顯示在最上層,這個header里面包括一個陰影View--><includeandroid:id="@+id/header"layout="@layout/include_header" /></RelativeLayout>

雖然再簡單不過了,還是稍微分析一下,header包括內(nèi)容48dp和陰影8dp,那么marginTop就是48dp了。

下面給大家介紹Android給ListView設(shè)置分割線Divider樣式

給ListView設(shè)置分割線,只需設(shè)置如下兩個屬性:

android:divider="#000" //設(shè)置分割線顯示顏色
android:dividerHeight="1px" //此處非0,否則無效

<ListView android:id="@+id/listView"    android:layout_width="fill_parent"   android:layout_height="fill_parent"    android:divider="#FFF"   android:dividerHeight="1px"   android:layout_margin="10dip"/>

以上內(nèi)容給大家簡單介紹了Android中的Divider,希望對大家有所幫助!

發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 安丘市| 府谷县| 山西省| 伊宁县| 高陵县| 宣恩县| 交口县| 石门县| 永昌县| 东丰县| 临沂市| 沂水县| 进贤县| 泗水县| 枣庄市| 无锡市| 河间市| 贞丰县| 花垣县| 邹平县| 灵璧县| 泽库县| 梓潼县| 合江县| 石河子市| 措美县| 新绛县| 湘潭市| 陇南市| 东至县| 南汇区| 全南县| 巨野县| 嘉禾县| 龙岩市| 七台河市| 车致| 大关县| 呼玛县| 禹州市| 贞丰县|