Android Recyclerview 網格佈局分割線

来源:https://www.cnblogs.com/liuwa/archive/2018/03/01/8489567.html
-Advertisement-
Play Games

1上一篇仿微信圖片選擇器的時候分割線出了點bug,其實是我把一塊關鍵代碼刪掉了,不過無關緊要,這次單獨寫一篇 2csdn上hongyang大神已經寫過了,但是按照他寫的方法我自己試了一下網格佈局的有點問題,具體是什麼問題已經記不清了(沒有質疑大神代碼的意思,貌似是他的代碼有一個方法過期了),我這個是 ...


1上一篇仿微信圖片選擇器的時候分割線出了點bug,其實是我把一塊關鍵代碼刪掉了,不過無關緊要,這次單獨寫一篇

2csdn上hongyang大神已經寫過了,但是按照他寫的方法我自己試了一下網格佈局的有點問題,具體是什麼問題已經記不清了(沒有質疑大神代碼的意思,貌似是他的代碼有一個方法過期了),我這個是自己親測沒問題的

3步驟,新建一個DiciderGridItemDecoration

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.annotation.IntDef;
import android.support.v4.view.ViewCompat;
import android.support.v7.widget.GridLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.StaggeredGridLayoutManager;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.View;

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

/**
 * Created by MAC on 2018/2/5.
 */

public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {
    private static final int[] ATTRS = new int[]{android.R.attr.listDivider}; //這個就是設置樣式的地方(顏色,寬度等等)
    public static final int GRID_DIVIDER_HORIZONTAL = GridLayoutManager.HORIZONTAL;
    public static final int GRID_DIVIDER_VERTICAL = GridLayoutManager.VERTICAL;

    private final SparseIntArray mHorizontalDividerOffsets = new SparseIntArray();
    private final SparseIntArray mVerticalDividerOffsets = new SparseIntArray();

    private final SparseArray<DrawableCreator> mTypeDrawableFactories = new SparseArray<>();

    @IntDef({
            GRID_DIVIDER_HORIZONTAL,
            GRID_DIVIDER_VERTICAL
    })
    @Retention(RetentionPolicy.SOURCE)
    private @interface Orientation {
    }

    @Orientation
    private int mOrientation;
    private Drawable mHorizontalDivider;
    private Drawable mVerticalDivider;

    public DividerGridItemDecoration(Context context, @Orientation int orientation) {
        resolveDivider(context);
        setOrientation(orientation);
    }

    private void resolveDivider(Context context) {
        final TypedArray a = context.obtainStyledAttributes(ATTRS);
        mVerticalDivider = mHorizontalDivider = a.getDrawable(0);
        a.recycle();
    }

    public void setOrientation(int orientation) {
        this.mOrientation = orientation;
    }

    public void setVerticalDivider(Drawable verticalDivider) {
        this.mVerticalDivider = verticalDivider;
    }

    public void setHorizontalDivider(Drawable horizontalDivider) {
        this.mHorizontalDivider = horizontalDivider;
    }

    @Override
    public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
        drawHorizontalDividers(c, parent);
        drawVerticalDividers(c, parent);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        final int spanCount = getSpanCount(parent);
        final int childCount = parent.getAdapter().getItemCount();
        final int adapterPosition = parent.getChildAdapterPosition(view);

        if (mHorizontalDividerOffsets.indexOfKey(adapterPosition) < 0) {
            mHorizontalDividerOffsets.put(adapterPosition, getHorizontalDivider(parent, adapterPosition).getIntrinsicHeight());
        }

        if (mVerticalDividerOffsets.indexOfKey(adapterPosition) < 0) {
            mVerticalDividerOffsets.put(adapterPosition, getVerticalDivider(parent, adapterPosition).getIntrinsicHeight());
        }

        outRect.set(0, 0, mHorizontalDividerOffsets.get(adapterPosition), mVerticalDividerOffsets.get(adapterPosition));

        if (isLastRow(adapterPosition, spanCount, childCount)) {
            outRect.bottom = 0;
        }

        if (isLastColumn(adapterPosition, spanCount, childCount)) {
            outRect.right = 0;
        }

    }

    private boolean isLastColumn(int position, int spanCount, int childCount) {
        if (mOrientation == GRID_DIVIDER_VERTICAL) {
            return (position + 1) % spanCount == 0;
        } else {
            int lastColumnCount = childCount % spanCount;
            lastColumnCount = lastColumnCount == 0 ? spanCount : lastColumnCount;
            return position >= childCount - lastColumnCount;
        }
    }

    private boolean isLastRow(int position, int spanCount, int childCount) {
        if (mOrientation == GRID_DIVIDER_VERTICAL) {
            int lastColumnCount = childCount % spanCount;
            lastColumnCount = lastColumnCount == 0 ? spanCount : lastColumnCount;
            return position >= childCount - lastColumnCount;
        } else {
            return (position + 1) % spanCount == 0;
        }
    }

    private int getSpanCount(RecyclerView parent) {
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();

        if (layoutManager instanceof GridLayoutManager) {
            return ((GridLayoutManager) layoutManager).getSpanCount();
        } else if (layoutManager instanceof StaggeredGridLayoutManager) {
            return ((StaggeredGridLayoutManager) layoutManager).getSpanCount();
        } else {
            throw new UnsupportedOperationException("the GridDividerItemDecoration can only be used in " +
                    "the RecyclerView which use a GridLayoutManager or StaggeredGridLayoutManager");
        }
    }

    public void drawVerticalDividers(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 Drawable divider = getVerticalDivider(parent, params.getViewAdapterPosition());
            final int top = child.getBottom() + params.bottomMargin + Math.round(ViewCompat.getTranslationY(child));
            final int bottom = top + divider.getIntrinsicHeight();

            mVerticalDividerOffsets.put(params.getViewAdapterPosition(), divider.getIntrinsicHeight());

            divider.setBounds(left, top, right, bottom);
            divider.draw(c);
        }
    }

    public void drawHorizontalDividers(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 Drawable divider = getHorizontalDivider(parent, params.getViewAdapterPosition());
            final int left = child.getRight() + params.rightMargin + Math.round(ViewCompat.getTranslationX(child));
            final int right = left + divider.getIntrinsicHeight();

            mHorizontalDividerOffsets.put(params.getViewAdapterPosition(), divider.getIntrinsicHeight());

            divider.setBounds(left, top, right, bottom);
            divider.draw(c);
        }
    }

    private Drawable getVerticalDivider(RecyclerView parent, int adapterPosition) {
        RecyclerView.Adapter adapter = parent.getAdapter();
        int itemType = adapter.getItemViewType(adapterPosition);
        DrawableCreator drawableCreator = mTypeDrawableFactories.get(itemType);

        if (drawableCreator != null) {
            return drawableCreator.createVertical(parent, adapterPosition);
        }

        return mVerticalDivider;
    }

    private Drawable getHorizontalDivider(RecyclerView parent, int adapterPosition) {
        RecyclerView.Adapter adapter = parent.getAdapter();
        int itemType = adapter.getItemViewType(adapterPosition);
        DrawableCreator drawableCreator = mTypeDrawableFactories.get(itemType);

        if (drawableCreator != null) {
            return drawableCreator.createHorizontal(parent, adapterPosition);
        }

        return mHorizontalDivider;
    }

    public void registerTypeDrawable(int itemType, DrawableCreator drawableCreator) {
        mTypeDrawableFactories.put(itemType, drawableCreator);
    }

    public interface DrawableCreator {
        Drawable createVertical(RecyclerView parent, int adapterPosition);

        Drawable createHorizontal(RecyclerView parent, int adapterPosition);
    }

}

4下一步 在drawable文件夾下新建分割線樣式 ,divider_bg.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient //說來慚愧,這個是設置漸變色的,為了省事我直接把三個色改成相同顏色(正常寫corners,solid,stroke這些應該也是可以的我自己沒試)
        android:centerColor="#F5F6F6"
        android:endColor="#F5F6F6"
        android:startColor="#F5F6F6"
        android:type="linear" />
    <size android:height="4dp"/>

</shape>

5下一步 在manifests 的 application里找到them,點擊進入並修改

<style name="PlayerTheme" parent="Theme.AppCompat.NoActionBar">
        <item name="android:windowAnimationStyle">@style/PlayerAnimation</item>
        <item name="android:listDivider">@drawable/divider_bg</item>//主要就是加上這句話,其他的代碼跟分割線無關(具體的可以看hongyang大神的博客)
    </style>

6使用

binding.recyclerview.setLayoutManager(new GridLayoutManager(context, 2));
binding.recyclerview.addItemDecoration(new DividerGridItemDecoration(context, DividerGridItemDecoration.GRID_DIVIDER_VERTICAL));//最後這個參數應該就是設置分割線的方向的,如果是不變色的分割線怎麼設置無所謂,變色的線就自己決定方向吧

7總結一下,其實非常的簡單,把DividerGridItemDecoration複製一下,寫一個樣式,把樣式添加到them里,然後一行代碼調用


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 透明網關概念 ORACLE透明網關(Oracle Transparent Gateway)可以解決ORACLE資料庫和非ORACLE資料庫交互數據的需求。在一個異構的分散式環境中,通過ORACLE透明網關可以訪問其他類型資料庫,例如DB2,SQL Server、Sybase....。這個類似於SQL... ...
  • 如果想在一個已經建好的表中添加一列,可以用以下代碼: alter table 表名 add column 列名 varchar(20) not null; 這條語句會向已有的表中加入一列,這一列在表的最後一列位置。如果我們希望添加在指定的一列,可以用: alter table 表名 add colu ...
  • 去年買了一本講SqlServer的書,這幾天把這本塵封已久的書拿了出來,準備按照上面的目錄擼一遍。 簡單的看了下這本書的目錄結構,一共是九個部分 資料庫安裝 建立資料庫和處理數據 高級T SQL T SQL編程 企業數據管理 SQL Server安全 監視和審計 性能調整和優化 商業智能 資料庫文件 ...
  • iPhone將具有支持不同類型多線程API的能力,這些API包括:POSIX線程,NSObject,NSThread和NSOperation. iPhone操作系統是一個真正的搶占式,多任務操作系統,允許開發人員創建多線程應用。 拿著一個iPhone時,我手中實際是 一個配備Unix操作系統的搶占式 ...
  • 首先說一個很有意思的問題:一塊720p的屏幕和1080p的屏幕那個大? 這個問題很有代表性,如果手機豎著放,720p=720px*1280px,而1080p=1080px*1920px;那麼在寬度上,前者是720個像素,後者是1080個像素,後者一定比前者大嗎? 答案是否定的,後者不一定比前者大,還 ...
  • uCrop使用 github地址 https://github.com/Yalantis/uCrop然後clone或下載到本地,運行之。 效果預覽 app/build.gradle AndroidManifest.xml 這裡theme可以改成自己的 配置uCrop 其他配置 onActivityR ...
  • JAVAHow to Improve the Performance of a Java ApplicationJava Memory ManagementWriting Java Microservices With WSO2 Microservices Framework for Java (M... ...
  • 基於UIView類:WKJBatteryView WKJBatteryView.h WKJBatteryView.m 落日熔金,暮雲合璧,人在何處。 染柳煙濃,吹梅笛怨,春意知幾許。 元宵佳節,融和天氣,次第豈無風雨。 來相召、香車寶馬,謝他酒朋詩侶。中州盛日,閨門多暇,記得偏重三五。 鋪翠冠兒,捻 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...