Android 中為RecyclerView控制元件新增分隔線
在上一篇 RecyclerView 控制元件的文章中,我們看了一下ListView控制元件和RecyclerView控制元件的簡單用法,那麼下面我們將關注點放在RecyclerView上,畢竟RecyclerView控制元件在很多方面確實比ListView控制元件更好用。下面來看一下怎麼對RecyclerView中的子項新增分隔線:
首先,我們要知道,要對RecyclerView控制元件中的子項新增分隔線,我們要利用RecyclerView.ItemDecoration類來實現。我們要繼承RecyclerView.ItemDecoration類並且重寫裡面的方法來實現,一般來說,一個自定義的ItemDecoration類的基本寫法:
public class ItemDecoration extends RecyclerView.ItemDecoration {
// 在這個方法中繪製分隔線,這個方法會在RecyclerView中的子項繪製完成之前被呼叫
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
}
// 也可以在這個方法中繪製分隔線,這個方法會在RecyclerView中的子項繪製完成之後被呼叫
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDrawOver(c, parent, state);
}
// 這個方法用於對子項的繪製位置進行一些必要的調整或者對子項進行一些其他的調整。第一個引數為子項的繪製位置,第二個引數為正在繪製的子項View的引用
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super .getItemOffsets(outRect, view, parent, state);
}
}
其實,onDraw 和 onDrawOver 方法我們只需要重寫其中一個就行了,因為兩個方法唯一的不同就是呼叫的先後問題。下面用一個小例子來看一下RecyclerView.ItemDecoration類的具體用法,新建一個Android工程:
首先,如果我們要使用RecyclerView控制元件,我們必須對它新增構建依賴:
在Android studio 工程中的app目錄下的buil.gradle檔案中加上上圖劃出的程式碼,之後點選右上角的 async now 藍色字型,android studio 就會為我們新增對RecyclerView控制元件的依賴,我們就可以在程式中使用它,下面是 activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_main"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center_horizontal"
tools:context="com.example.administrator.blogrecyclerview.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</android.support.v7.widget.RecyclerView>
</LinearLayout>
可以看到,我們在佈局檔案中只加入了一個RecyclerView控制元件,接下來要為 RecyclerView 控制元件準備顯示的資料,通過RecyclerView.Adapter<RecyclerView.ViewHolder> 這個RecyclerView 自帶的介面卡類來實現如果對這個類的使用還不是很熟悉的,可以看一下http://blog.csdn.net/hacker_zhidian/article/details/56292052這篇文章,ok,我們繼續,新建一個佈局檔案item_layout.xml作為RecyclerView控制元件的子項檢視:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:textSize="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
為了簡單起見,我們只是使用一個TextView控制元件,這樣的話RecyclerView的子項就只能顯示文字,當然我們可以根據需求定製佈局檔案。接下來是自定義的介面卡類MyRecyclerViewAdapter.java:
import android.content.Context;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
import android.widget.Toast;
import java.util.ArrayList;
/**
* Created by Administrator on 2017/2/26.
*/
public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyViewHolder> {
private Context myContext = null;
private ArrayList<String> textViewList = null;
public MyRecyclerViewAdapter(Context context, ArrayList<String> list) {
myContext = context;
textViewList = list;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).
inflate(R.layout.item_layout, parent, false);
view.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Toast.makeText(myContext, ((TextView) v.findViewById(R.id.textView)).getText(),
Toast.LENGTH_SHORT).show();
}
});
MyViewHolder myViewHolder = new MyViewHolder(view);
return myViewHolder;
}
@Override
public void onBindViewHolder(MyViewHolder holder, int position) {
holder.textView.setText(textViewList.get(position));
}
@Override
public int getItemCount() {
return textViewList.size();
}
}
class MyViewHolder extends RecyclerView.ViewHolder{
public TextView textView;
public MyViewHolder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.textView);
}
};
這裡就不多介紹了,在前文的連結中有對於RecyclerView.Adapter類的介紹,那麼最後就是MainActivity.java了:
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.widget.LinearLayout;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ArrayList<String> stringList = new ArrayList<String>();
private RecyclerView recyclerView = null;
private MyRecyclerViewAdapter myRecyclerViewAdapter = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
initAdapter();
// 新建一個線性佈局管理器,並且設定排布方向為豎直方向
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);
linearLayoutManager.setOrientation(LinearLayoutManager.VERTICAL);
recyclerView.setLayoutManager(linearLayoutManager); // 設定子項排布方向
recyclerView.setAdapter(myRecyclerViewAdapter); // 設定介面卡
}
public void initAdapter() { // 初始化顯示的資料和介面卡
String str = null;
for(int i = 0; i < 20; i++) {
str = "專案" + (i+1);
stringList.add(str);
}
myRecyclerViewAdapter = new MyRecyclerViewAdapter(this, stringList);
}
}
好了,我們先來看一下效果:
可以看到,我們這裡的顯示子項之中並沒有分割線,那麼怎麼新增分割線呢?我們對文章開始的繼承於 RecyclerView.ItemDecoration 類的自定義類來進行改寫,加入我們自己的邏輯:
在工程中新建一個類MyItemDecoration.java:
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
/**
* Created by Administrator on 2017/2/26.
*/
public class MyItemDecoration extends RecyclerView.ItemDecoration {
/*
* 定義4個常量值,代表佈局方向,分別是豎向線性佈局、橫向線性佈局、豎向網格佈局、橫向網格佈局
*/
public static final int LINEAR_LAYOUT_ORIENTATION_VERTICAL = 0;
public static final int LINEAR_LAYOUT_ORIENTATION_HORIZONTAL = 1;
public static final int GRID_LAYOUT_ORIENTATION_VERTICAL = 2;
public static final int GRID_LAYOUT_ORIENTATION_HORIZONTAL = 3;
private int orientation = -1; // 當前的佈局方向
// 如果是網格佈局我們要計算出每一行或者每一列(取決於佈局方向)中的子項數目
private int rawOrColumnSum = 0;
// Drawable 物件用於繪製分隔線
private Drawable myDivider = null;
public MyItemDecoration(Context context, int orientation) {
/* 這個構造方法用於處理線性佈局傳入的情況,我們要對myDivider物件進行初始化
* (繪製的顏色和寬度等等)
* R.drawable.my_list_divider 是我們自定義的一個drawable資原始檔,我們通過
* myContext來獲取它
*/
myDivider = context.getResources().getDrawable(R.drawable.my_list_divider);
if(orientation == LinearLayoutManager.HORIZONTAL) {
this.orientation = LINEAR_LAYOUT_ORIENTATION_HORIZONTAL;
}else if(orientation == LinearLayoutManager.VERTICAL) {
this.orientation = LINEAR_LAYOUT_ORIENTATION_VERTICAL;
}
}
public MyItemDecoration(Context context, int orientation, int rawOrColumnSum) {
// 這個構造方法用於處理網格佈局傳入的情況,原理同上
myDivider = context.getResources().getDrawable(R.drawable.my_list_divider);
if(orientation == GridLayoutManager.HORIZONTAL) {
this.orientation = GRID_LAYOUT_ORIENTATION_HORIZONTAL;
} else if(orientation == GridLayoutManager.VERTICAL) {
this.orientation = GRID_LAYOUT_ORIENTATION_VERTICAL;
}
this.rawOrColumnSum = rawOrColumnSum;
}
// 在這個方法中。我們對佈局方向進行判斷,由此來呼叫正確的分隔線繪製方法
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if(orientation == LINEAR_LAYOUT_ORIENTATION_HORIZONTAL ||
orientation == LINEAR_LAYOUT_ORIENTATION_VERTICAL) {
linearLayoutDrawItemDecoration(c, parent);
} else if(orientation == GRID_LAYOUT_ORIENTATION_HORIZONTAL ||
orientation == GRID_LAYOUT_ORIENTATION_VERTICAL) {
gridLayoutItemDecoration(c, parent);
}
}
/*
* 當排布方式為線性佈局的時候,繪製分割線的方法:
*/
private void linearLayoutDrawItemDecoration(Canvas canvas, RecyclerView parent) {
int childCount = parent.getChildCount(); // 獲取RecyclerView控制元件中的子控制元件總數
int left, top, right, bottom;
View child = parent.getChildAt(0);
// 獲取分割線的高度(把分割線看成一個小矩形)
int drawableHeight = myDivider.getIntrinsicHeight();
// 如果是豎直排布,那麼分割線為橫線
if(orientation == LINEAR_LAYOUT_ORIENTATION_VERTICAL) {
left = parent.getLeft();
right = parent.getRight(); // 獲取子控制元件開始 x 座標和結束 x 座標
for (int i = 1; i < childCount; i++) {
top = child.getBottom() - drawableHeight/2; // 獲取開始點y座標
bottom = child.getBottom() + drawableHeight/2; // 獲取結束點y座標
myDivider.setBounds(left, top, right, bottom); // 設定繪製區域,下同
myDivider.draw(canvas); // 在Canvas物件上繪製區域
child = parent.getChildAt(i);
}
// 如果是水平排布,那麼分割線為豎線
} else if(orientation == LINEAR_LAYOUT_ORIENTATION_HORIZONTAL) {
top = child.getTop();
bottom = child.getBottom(); // 獲取子控制元件的開始 y 座標和結束 y 座標
for(int i = 1; i < childCount; i++) {
left = child.getRight() - drawableHeight/2; // 獲取開始點 x 座標
right = child.getRight() + drawableHeight/2; // 獲取結束點 x 座標
myDivider.setBounds(left, top, right, bottom); // 設定繪製區域
myDivider.draw(canvas);
child = parent.getChildAt(i);
}
}
}
/*
* 當排布方式為網格佈局的時候,分割線的繪製方法:
*/
private void gridLayoutItemDecoration(Canvas canvas, RecyclerView parent) {
// 順著佈局方向上的要繪製的分割線條數
int childCount = parent.getChildCount();
int lineSum = childCount / rawOrColumnSum - 1;
lineSum += childCount % rawOrColumnSum == 0 ? 0 : 1;
// 獲取分割線的高度(把分割線看成一個小矩形)
int drawableHeight = myDivider.getIntrinsicHeight();
int left, right, top, bottom;
View child = parent.getChildAt(0);
// 佈局方向為豎直排布方式
if(orientation == GRID_LAYOUT_ORIENTATION_VERTICAL) {
left = parent.getLeft();
right = parent.getRight();
for(int i = 0; i < lineSum; i++) { // 迴圈用於繪製橫向分割線
child = parent.getChildAt(i*rawOrColumnSum);
top = child.getBottom() - drawableHeight/2;
bottom = child.getBottom() + drawableHeight/2;
myDivider.setBounds(left, top, right, bottom);
myDivider.draw(canvas);
}
top = parent.getTop();
bottom = parent.getBottom();
for(int i = 0; i < rawOrColumnSum-1; i++) { // 迴圈用於繪製豎向分割線
child = parent.getChildAt(i);
left = child.getRight() - drawableHeight/2;
right = child.getRight() + drawableHeight/2;
myDivider.setBounds(left, top, right, bottom);
myDivider.draw(canvas);
}
// 佈局方向為橫向排布方式
} else if(orientation == GRID_LAYOUT_ORIENTATION_HORIZONTAL) {
top = parent.getTop();
bottom = parent.getBottom();
for(int i = 0; i <= lineSum; i++) { // 迴圈繪製豎向分割線
child = parent.getChildAt(i*rawOrColumnSum);
left = child.getRight() - drawableHeight/2;
right = child.getRight() + drawableHeight/2;
myDivider.setBounds(left, top, right, bottom);
myDivider.draw(canvas);
}
left = parent.getLeft();
right = parent.getRight();
for(int i = 0; i < rawOrColumnSum; i++) { // 迴圈繪製橫向分割線
child = parent.getChildAt(i);
top = child.getBottom() - drawableHeight/2;
bottom = child.getBottom() + drawableHeight/2;
myDivider.setBounds(left, top, right, bottom);
myDivider.draw(canvas);
}
}
}
}
程式碼看似有點多,但是主要的邏輯不復雜:對RecyclerView的子項排布方式進行判斷,兩個方法分別用於繪製線性佈局的分隔線和網格佈局的分隔線,這兩個方法主要是通過佈局和控制元件的位置來計算出myDivider繪製的區域的一些位置資訊,如果對於佈局和控制元件的熟悉的話就沒什麼難點了。我們注意到這裡的分隔線使用了我們自定義的資源,因此,我們要在drawable資料夾中新建一個資原始檔my_list_divider.xm:
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<size android:height="4dp"></size>
<gradient
android:startColor="#ff0000"
android:centerColor="#00ff00"
android:endColor="#0000ff">
</gradient>
</shape>
我們在這個資原始檔中設定了myDivider物件的線寬(4dp)和顏色(紅、綠、藍的漸變顏色效果),OK, 一個RecyclerView控制元件的分隔線繪製就完成了,我麼還需要對MainActivity.java進行小小的修改才能顯示出分割線的效果:
就是為我們RecyclerView控制元件新增一個MyItemDecoration物件來實現分割線的繪製,好了,讓我們執行一下:
這裡為了顯示出滑動的效果,故意多加了點資料,這裡是RecyclerView控制元件中的子項排布方式為豎值的分隔線效果,那麼水平呢?讓我們來改一下MainActivity.java:
改了一下線性佈局的排布方式,為了美觀,我們還需要對item_layout.xml進行更改:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:textSize="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
再執行試試:
因為顯示原因,看起來子項滑動的時候分割線好像斷了一樣,實際上並沒有這個bug。ok,下面來試試網格佈局:
在MainActivity中加了一個網格佈局,並且設定排布方向和每一行顯示的子項數,之後呼叫了MyItemDecoration的第二個適用於網格佈局的構造方法。為了美觀,我們還得對item_layout.xml檔案進行改動:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:id="@+id/textView"
android:textSize="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
來看看效果:
ok, 最後,來看一下網格佈局的橫向排布方式的效果,MainActivity.java 只需要改動一個網格佈局的排布方向就行了,這裡就不貼了,之後為了美觀還得改一下item_layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:paddingLeft="10dp"
android:paddingRight="10dp"
android:layout_width="wrap_content"
android:layout_height="match_parent">
<TextView
android:id="@+id/textView"
android:textSize="40sp"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
好了,來看看效果:
好了,RecyclerView控制元件的分隔線就介紹的差不多了,RecyclerView控制元件相當於ListView控制元件的升級版,使用步驟也類似:定義控制元件、使用介面卡新增資料、添加布局管理器、新增分隔線、新增動畫效果等等,正是因為這種完全的解耦機制才成就了它的靈活性。我們可以通過自己的需求來定義效果。
如果部落格中有什麼不正確的地方,還請多多指點。
謝謝觀看。。。
相關推薦
Android 中為RecyclerView控制元件新增分隔線
在上一篇 RecyclerView 控制元件的文章中,我們看了一下ListView控制元件和RecyclerView控制元件的簡單用法,那麼下面我們將關注點放在RecyclerView上,畢竟RecyclerView控制元件在很多方面確實比ListView控制元
MFC在VS2010中為ActiveX控制元件新增屬性
ActiveX控制元件有四種屬性: (1)Stock:為每個控制元件提供的標準屬性,如字型或顏色。 (2)Ambient:圍繞控制元件的環境屬性——已被置入容器的屬性。這些屬性不能被更改,但控制元件可以使用它們調整自己的屬性。 (3)Extended:這些是由容器處
Android中使用ImageView控制元件顯示網路圖片
在android4.0以後的版本中,為了使得主介面流暢,所以設定了不允許在主執行緒中訪問網路,為了安全,又不允許在其它執行緒中訪問控制元件,這樣就造成了ImageView等需要使用網路的控制元件更新時的問題,本文以Handler+Runnable的方式實現了ImageView控制元件顯示網路圖片.
IOS開發學習筆記十五 為UITableView控制元件新增Header和Footer
效果圖:專案地址 新增圖片素材,新增plist檔案,新增名為CZGoods的module檔案 @implementation CZGoods - (instancetype)initWithDict:(NSDictionary *)dict { if
Android中自定義控制元件SegmentedGroup
GitHub:https://github.com/Kaopiz/android-segmented-control 一 、新增依賴 implementation 'info.hoang8f:android-segmented:1.0.6' 二、佈局中使用 <info.hoan
Android中findViewById()獲取控制元件後 報 空指標 錯誤
今天再做一個程式時,發現我使用findViewById(R.id.edit)獲取EditText時總是報空指標錯誤,我想不可能啊!! 最後從findViewById()下手,才發現原來此方法中的R.id.edit是從當前Activity或者Dialog的主佈局檔案xml中獲
android 中如何設定控制元件的字型和背景樣式
1.設定背景圖片,圖片來源於drawable; button.setBackgroundDrawable(getResources().getDrawable(R.drawable.search_l
為ActiveX控制元件新增Cab檔案
INF 檔案是一個文字檔案,用以指定為控制元件的執行而需要顯示或下載的檔案(如 DLL 檔案或其他 OCX 檔案)。INF 檔案使您得以將所有所需的檔案捆綁在一個壓縮的 CAB 檔案中。預設情況下,版本號同用戶硬碟上的現有檔案相同的檔案不下載。有關 INF 檔案及其選項的更多資訊,包括如何建立與平臺無關的 I
Android中動態改變控制元件的大小的一種方法
在Android中有時候我們需要動態改變控制元件的大小。有幾種辦法可以實現 一是在onMeasure中修改尺寸,二是在onLayout中修改位置和尺寸。這個是可以進行位置修改的,onMeasure不行。 還有一種是用LayoutParams來進行修改。前兩種方法都
Android 中動態設定控制元件高寬
在Android中,像文字,按鈕這種控制元件我們可以直接用setWidth和setHeight,但是某些控制元件比如說ImageView,ImageViewButton等等,可以在佈局檔案中設定android:layout_width="xx",但是並沒有提供setWidt
listview中多個控制元件新增靜態陣列
最終效果如下圖所示: 具體步驟: 一 建立activity.xml和item_layout.xml佈局檔案 二 建立資料來源格式類Card 三 配置介面卡CardAdapter 在修改getview方法中:首先要為資料定
Android中的獲取控制元件矩陣gethitrect方法
原文地址:http://souly.cn/%E6%8A%80%E6%9C%AF%E5%8D%9A%E6%96%87/2015/07/31/Android%E4%B8%AD%E7%9A%84%E8%8E%B7%E5%8F%96%E6%8E%A7%E4%BB%B6%E7%9F%
為ListBox控制元件新增水平滾動條
Win32的標準控制元件之中,列表控制元件(ListBox)並沒有和列表檢視(ListView)一樣提供水平滾動條,所以如果列表項的長度超過列表的寬度的話,那麼超出的部分將無法顯示。在本文中我將以一個簡單的例子來說明如何使用SDK來解決這一問題,在這個例子中,我將為一個列表控
Android中自定義控制元件
作為一個有創意的開發者,或者軟體對UI設計的要求比較高,你經常會遇到安卓自帶的控制元件無法滿足你的需求的情況,這種時候,我們只能去自己去實現適合專案的控制元件。同時,安卓也允許你去繼承已經存在的控制元件或者實現你自己的控制元件以便優化介面和創造更加豐富的使用者體驗。 那麼
為ActiveX控制元件新增對話方塊
1 在資源rc中 新增對話方塊 並向對話方塊上拖放一個按鈕 對話方塊的屬性做下修改:Border改為None,Control改為Ture,Style改為Child,System改為False,Visible改為True,然後在對話方塊中雙擊,為對話方塊新增一個類(將會自動開
Android 中獲取EditText控制元件的焦點以及監聽他的內容讓焦點自動跳轉到下一個EditText控制元件
最近在弄EditText控制元件,監聽他的輸入內容,在輸入3個字元的時候就自動將焦點跳到另一個EditText文字框裡面,找了好久,才弄到程式碼: xml 檔案: <EditText android:id="@+id
Android中的文字控制元件
Typeface tf=Typeface.createFromAsset(getAssets(), "字型名稱.ttf");//根據路徑得到Typeface textview.setTypeface(tf);
Android通過xml給控制元件新增邊框
通過Android 中自定義的屬性給ImageView設定上下左右邊框,請參照下面的程式碼,同樣是在drawable資料夾下建立shape型別的xml檔案,比如:img_border.xml,然後在該檔案中新增如下程式碼,同樣是通過android:backgro
android中 如何設定控制元件獲取焦點
舉例用的EditText控制元件 直接上程式碼: private EditText et_pwd; et_pwd = (EditText) findViewById(R.id.password_edit); et_pwd.setFocusable(true); et_p
android如何為listview的每項中edittext控制元件新增textwacher
listview中的每項都有一個edittext,而且現在需要實時監聽該edittext的輸入,在listview的外部進行改變(例如使用者修改單價,外部的總價需要變化) 新增監聽器的程式碼: public View getView(final int position,