|
|
|
|
@ -1,413 +0,0 @@
|
|
|
|
|
/*
|
|
|
|
|
* Copyright (C) 2021 The Android Open Source Project
|
|
|
|
|
*
|
|
|
|
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
|
* you may not use this file except in compliance with the License.
|
|
|
|
|
* You may obtain a copy of the License at
|
|
|
|
|
*
|
|
|
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
|
*
|
|
|
|
|
* Unless required by applicable law or agreed to in writing, software
|
|
|
|
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
|
* See the License for the specific language governing permissions and
|
|
|
|
|
* limitations under the License.
|
|
|
|
|
*/
|
|
|
|
|
|
|
|
|
|
package com.google.android.material.divider;
|
|
|
|
|
|
|
|
|
|
import android.content.Context;
|
|
|
|
|
import android.content.res.TypedArray;
|
|
|
|
|
import android.graphics.Canvas;
|
|
|
|
|
import android.graphics.Rect;
|
|
|
|
|
import android.graphics.drawable.Drawable;
|
|
|
|
|
import android.graphics.drawable.ShapeDrawable;
|
|
|
|
|
import android.util.AttributeSet;
|
|
|
|
|
import android.view.View;
|
|
|
|
|
import android.widget.LinearLayout;
|
|
|
|
|
|
|
|
|
|
import androidx.annotation.ColorInt;
|
|
|
|
|
import androidx.annotation.ColorRes;
|
|
|
|
|
import androidx.annotation.DimenRes;
|
|
|
|
|
import androidx.annotation.NonNull;
|
|
|
|
|
import androidx.annotation.Nullable;
|
|
|
|
|
import androidx.annotation.Px;
|
|
|
|
|
import androidx.core.content.ContextCompat;
|
|
|
|
|
import androidx.core.graphics.drawable.DrawableCompat;
|
|
|
|
|
import androidx.core.view.ViewCompat;
|
|
|
|
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
|
|
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
|
|
|
import androidx.recyclerview.widget.RecyclerView.ItemDecoration;
|
|
|
|
|
|
|
|
|
|
import com.google.android.material.R;
|
|
|
|
|
import com.google.android.material.internal.ThemeEnforcement;
|
|
|
|
|
import com.google.android.material.resources.MaterialResources;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* MaterialDividerItemDecoration is a {@link RecyclerView.ItemDecoration}, similar to a {@link
|
|
|
|
|
* androidx.recyclerview.widget.DividerItemDecoration}, that can be used as a divider between items of
|
|
|
|
|
* a {@link LinearLayoutManager}. It supports both {@link #HORIZONTAL} and {@link #VERTICAL}
|
|
|
|
|
* orientations.
|
|
|
|
|
*
|
|
|
|
|
* <pre>
|
|
|
|
|
* dividerItemDecoration = new MaterialDividerItemDecoration(recyclerView.getContext(),
|
|
|
|
|
* layoutManager.getOrientation());
|
|
|
|
|
* recyclerView.addItemDecoration(dividerItemDecoration);
|
|
|
|
|
* </pre>
|
|
|
|
|
*
|
|
|
|
|
* Modified at several points by Alexander Capehart to backport miscellaneous fixes not currently
|
|
|
|
|
* obtainable in the currently used MDC library.
|
|
|
|
|
*/
|
|
|
|
|
public class BackportMaterialDividerItemDecoration extends ItemDecoration {
|
|
|
|
|
public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
|
|
|
|
|
public static final int VERTICAL = LinearLayout.VERTICAL;
|
|
|
|
|
|
|
|
|
|
private static final int DEF_STYLE_RES = R.style.Widget_MaterialComponents_MaterialDivider;
|
|
|
|
|
|
|
|
|
|
@NonNull private Drawable dividerDrawable;
|
|
|
|
|
private int thickness;
|
|
|
|
|
@ColorInt private int color;
|
|
|
|
|
private int orientation;
|
|
|
|
|
private int insetStart;
|
|
|
|
|
private int insetEnd;
|
|
|
|
|
private boolean lastItemDecorated;
|
|
|
|
|
|
|
|
|
|
private final Rect tempRect = new Rect();
|
|
|
|
|
|
|
|
|
|
public BackportMaterialDividerItemDecoration(@NonNull Context context, int orientation) {
|
|
|
|
|
this(context, null, orientation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BackportMaterialDividerItemDecoration(
|
|
|
|
|
@NonNull Context context, @Nullable AttributeSet attrs, int orientation) {
|
|
|
|
|
this(context, attrs, R.attr.materialDividerStyle, orientation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public BackportMaterialDividerItemDecoration(
|
|
|
|
|
@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr, int orientation) {
|
|
|
|
|
TypedArray attributes =
|
|
|
|
|
ThemeEnforcement.obtainStyledAttributes(
|
|
|
|
|
context, attrs, R.styleable.MaterialDivider, defStyleAttr, DEF_STYLE_RES);
|
|
|
|
|
|
|
|
|
|
color =
|
|
|
|
|
MaterialResources.getColorStateList(
|
|
|
|
|
context, attributes, R.styleable.MaterialDivider_dividerColor)
|
|
|
|
|
.getDefaultColor();
|
|
|
|
|
thickness =
|
|
|
|
|
attributes.getDimensionPixelSize(
|
|
|
|
|
R.styleable.MaterialDivider_dividerThickness,
|
|
|
|
|
context.getResources().getDimensionPixelSize(R.dimen.material_divider_thickness));
|
|
|
|
|
insetStart =
|
|
|
|
|
attributes.getDimensionPixelOffset(R.styleable.MaterialDivider_dividerInsetStart, 0);
|
|
|
|
|
insetEnd = attributes.getDimensionPixelOffset(R.styleable.MaterialDivider_dividerInsetEnd, 0);
|
|
|
|
|
lastItemDecorated =
|
|
|
|
|
attributes.getBoolean(R.styleable.MaterialDivider_lastItemDecorated, true);
|
|
|
|
|
|
|
|
|
|
attributes.recycle();
|
|
|
|
|
|
|
|
|
|
dividerDrawable = new ShapeDrawable();
|
|
|
|
|
setDividerColor(color);
|
|
|
|
|
setOrientation(orientation);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the orientation for this divider. This should be called if {@link
|
|
|
|
|
* RecyclerView.LayoutManager} changes orientation.
|
|
|
|
|
*
|
|
|
|
|
* <p>A {@link #HORIZONTAL} orientation will draw a vertical divider, and a {@link #VERTICAL}
|
|
|
|
|
* orientation a horizontal divider.
|
|
|
|
|
*
|
|
|
|
|
* @param orientation The orientation of the {@link RecyclerView} this divider is associated with:
|
|
|
|
|
* {@link #HORIZONTAL} or {@link #VERTICAL}
|
|
|
|
|
*/
|
|
|
|
|
public void setOrientation(int orientation) {
|
|
|
|
|
if (orientation != HORIZONTAL && orientation != VERTICAL) {
|
|
|
|
|
throw new IllegalArgumentException(
|
|
|
|
|
"Invalid orientation: " + orientation + ". It should be either HORIZONTAL or VERTICAL");
|
|
|
|
|
}
|
|
|
|
|
this.orientation = orientation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public int getOrientation() {
|
|
|
|
|
return orientation;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the thickness of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param thickness The thickness value to be set.
|
|
|
|
|
* @see #getDividerThickness()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerThickness
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerThickness(@Px int thickness) {
|
|
|
|
|
this.thickness = thickness;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the thickness of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param thicknessId The id of the thickness dimension resource to be set.
|
|
|
|
|
* @see #getDividerThickness()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerThickness
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerThicknessResource(@NonNull Context context, @DimenRes int thicknessId) {
|
|
|
|
|
setDividerThickness(context.getResources().getDimensionPixelSize(thicknessId));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the thickness set on the divider.
|
|
|
|
|
*
|
|
|
|
|
* @see #setDividerThickness(int)
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerThickness
|
|
|
|
|
*/
|
|
|
|
|
@Px
|
|
|
|
|
public int getDividerThickness() {
|
|
|
|
|
return thickness;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the color of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param color The color to be set.
|
|
|
|
|
* @see #getDividerColor()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerColor
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerColor(@ColorInt int color) {
|
|
|
|
|
this.color = color;
|
|
|
|
|
dividerDrawable = DrawableCompat.wrap(dividerDrawable);
|
|
|
|
|
DrawableCompat.setTint(dividerDrawable, color);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the color of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param colorId The id of the color resource to be set.
|
|
|
|
|
* @see #getDividerColor()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerColor
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerColorResource(@NonNull Context context, @ColorRes int colorId) {
|
|
|
|
|
setDividerColor(ContextCompat.getColor(context, colorId));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the divider color.
|
|
|
|
|
*
|
|
|
|
|
* @see #setDividerColor(int)
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerColor
|
|
|
|
|
*/
|
|
|
|
|
@ColorInt
|
|
|
|
|
public int getDividerColor() {
|
|
|
|
|
return color;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the start inset of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param insetStart The start inset to be set.
|
|
|
|
|
* @see #getDividerInsetStart()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetStart
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerInsetStart(@Px int insetStart) {
|
|
|
|
|
this.insetStart = insetStart;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the start inset of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param insetStartId The id of the inset dimension resource to be set.
|
|
|
|
|
* @see #getDividerInsetStart()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetStart
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerInsetStartResource(@NonNull Context context, @DimenRes int insetStartId) {
|
|
|
|
|
setDividerInsetStart(context.getResources().getDimensionPixelOffset(insetStartId));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the divider's start inset.
|
|
|
|
|
*
|
|
|
|
|
* @see #setDividerInsetStart(int)
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetStart
|
|
|
|
|
*/
|
|
|
|
|
@Px
|
|
|
|
|
public int getDividerInsetStart() {
|
|
|
|
|
return insetStart;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the end inset of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param insetEnd The end inset to be set.
|
|
|
|
|
* @see #getDividerInsetEnd()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetEnd
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerInsetEnd(@Px int insetEnd) {
|
|
|
|
|
this.insetEnd = insetEnd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets the end inset of the divider.
|
|
|
|
|
*
|
|
|
|
|
* @param insetEndId The id of the inset dimension resource to be set.
|
|
|
|
|
* @see #getDividerInsetEnd()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetEnd
|
|
|
|
|
*/
|
|
|
|
|
public void setDividerInsetEndResource(@NonNull Context context, @DimenRes int insetEndId) {
|
|
|
|
|
setDividerInsetEnd(context.getResources().getDimensionPixelOffset(insetEndId));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Returns the divider's end inset.
|
|
|
|
|
*
|
|
|
|
|
* @see #setDividerInsetEnd(int)
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_dividerInsetEnd
|
|
|
|
|
*/
|
|
|
|
|
@Px
|
|
|
|
|
public int getDividerInsetEnd() {
|
|
|
|
|
return insetEnd;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Sets whether the class should draw a divider after the last item of a {@link RecyclerView}.
|
|
|
|
|
*
|
|
|
|
|
* @param lastItemDecorated whether there's a divider after the last item of a recycler view.
|
|
|
|
|
* @see #isLastItemDecorated()
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_lastItemDecorated
|
|
|
|
|
*/
|
|
|
|
|
public void setLastItemDecorated(boolean lastItemDecorated) {
|
|
|
|
|
this.lastItemDecorated = lastItemDecorated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether there's a divider after the last item of a {@link RecyclerView}.
|
|
|
|
|
*
|
|
|
|
|
* @see #setLastItemDecorated(boolean)
|
|
|
|
|
* @attr ref com.google.android.material.R.styleable#MaterialDivider_shouldDecorateLastItem
|
|
|
|
|
*/
|
|
|
|
|
public boolean isLastItemDecorated() {
|
|
|
|
|
return lastItemDecorated;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void onDraw(
|
|
|
|
|
@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
|
|
|
|
|
if (parent.getLayoutManager() == null) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
if (orientation == VERTICAL) {
|
|
|
|
|
drawForVerticalOrientation(canvas, parent);
|
|
|
|
|
} else {
|
|
|
|
|
drawForHorizontalOrientation(canvas, parent);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a divider for the vertical orientation of the recycler view. The divider itself will be
|
|
|
|
|
* horizontal.
|
|
|
|
|
*/
|
|
|
|
|
private void drawForVerticalOrientation(@NonNull Canvas canvas, @NonNull RecyclerView parent) {
|
|
|
|
|
canvas.save();
|
|
|
|
|
int left;
|
|
|
|
|
int right;
|
|
|
|
|
if (parent.getClipToPadding()) {
|
|
|
|
|
left = parent.getPaddingLeft();
|
|
|
|
|
right = parent.getWidth() - parent.getPaddingRight();
|
|
|
|
|
canvas.clipRect(
|
|
|
|
|
left, parent.getPaddingTop(), right, parent.getHeight() - parent.getPaddingBottom());
|
|
|
|
|
} else {
|
|
|
|
|
left = 0;
|
|
|
|
|
right = parent.getWidth();
|
|
|
|
|
}
|
|
|
|
|
boolean isRtl = ViewCompat.getLayoutDirection(parent) == ViewCompat.LAYOUT_DIRECTION_RTL;
|
|
|
|
|
left += isRtl ? insetEnd : insetStart;
|
|
|
|
|
right -= isRtl ? insetStart : insetEnd;
|
|
|
|
|
|
|
|
|
|
int childCount = parent.getChildCount();
|
|
|
|
|
for (int i = 0; i < childCount; i++) {
|
|
|
|
|
View child = parent.getChildAt(i);
|
|
|
|
|
if (shouldDrawDivider(parent, child)) {
|
|
|
|
|
parent.getDecoratedBoundsWithMargins(child, tempRect);
|
|
|
|
|
// Take into consideration any translationY added to the view.
|
|
|
|
|
int bottom = tempRect.bottom + Math.round(child.getTranslationY());
|
|
|
|
|
int top = bottom - thickness;
|
|
|
|
|
dividerDrawable.setBounds(left, top, right, bottom);
|
|
|
|
|
dividerDrawable.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
canvas.restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draws a divider for the horizontal orientation of the recycler view. The divider itself will be
|
|
|
|
|
* vertical.
|
|
|
|
|
*/
|
|
|
|
|
private void drawForHorizontalOrientation(@NonNull Canvas canvas, @NonNull RecyclerView parent) {
|
|
|
|
|
canvas.save();
|
|
|
|
|
int top;
|
|
|
|
|
int bottom;
|
|
|
|
|
if (parent.getClipToPadding()) {
|
|
|
|
|
top = parent.getPaddingTop();
|
|
|
|
|
bottom = parent.getHeight() - parent.getPaddingBottom();
|
|
|
|
|
canvas.clipRect(
|
|
|
|
|
parent.getPaddingLeft(), top, parent.getWidth() - parent.getPaddingRight(), bottom);
|
|
|
|
|
} else {
|
|
|
|
|
top = 0;
|
|
|
|
|
bottom = parent.getHeight();
|
|
|
|
|
}
|
|
|
|
|
top += insetStart;
|
|
|
|
|
bottom -= insetEnd;
|
|
|
|
|
|
|
|
|
|
int childCount = parent.getChildCount();
|
|
|
|
|
for (int i = 0; i < childCount; i++) {
|
|
|
|
|
View child = parent.getChildAt(i);
|
|
|
|
|
if (shouldDrawDivider(parent, child)) {
|
|
|
|
|
parent.getDecoratedBoundsWithMargins(child, tempRect);
|
|
|
|
|
// Take into consideration any translationX added to the view.
|
|
|
|
|
int right = tempRect.right + Math.round(child.getTranslationX());
|
|
|
|
|
int left = right - thickness;
|
|
|
|
|
dividerDrawable.setBounds(left, top, right, bottom);
|
|
|
|
|
dividerDrawable.draw(canvas);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
canvas.restore();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@Override
|
|
|
|
|
public void getItemOffsets(
|
|
|
|
|
@NonNull Rect outRect,
|
|
|
|
|
@NonNull View view,
|
|
|
|
|
@NonNull RecyclerView parent,
|
|
|
|
|
@NonNull RecyclerView.State state) {
|
|
|
|
|
outRect.set(0, 0, 0, 0);
|
|
|
|
|
// Only add offset if there's a divider displayed.
|
|
|
|
|
if (shouldDrawDivider(parent, view)) {
|
|
|
|
|
if (orientation == VERTICAL) {
|
|
|
|
|
outRect.bottom = thickness;
|
|
|
|
|
} else {
|
|
|
|
|
outRect.right = thickness;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private boolean shouldDrawDivider(@NonNull RecyclerView parent, @NonNull View child) {
|
|
|
|
|
int position = parent.getChildAdapterPosition(child);
|
|
|
|
|
RecyclerView.Adapter<?> adapter = parent.getAdapter();
|
|
|
|
|
boolean isLastItem = adapter != null && position == adapter.getItemCount() - 1;
|
|
|
|
|
|
|
|
|
|
return position != RecyclerView.NO_POSITION
|
|
|
|
|
&& (!isLastItem || lastItemDecorated)
|
|
|
|
|
&& shouldDrawDivider(position, adapter);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Whether a divider should be drawn below the current item that is being drawn.
|
|
|
|
|
*
|
|
|
|
|
* <p>Note: if lasItemDecorated is false, the divider below the last item will never be drawn even
|
|
|
|
|
* if this method returns true.
|
|
|
|
|
*
|
|
|
|
|
* @param position the position of the current item being drawn.
|
|
|
|
|
* @param adapter the {@link RecyclerView.Adapter} associated with the item being drawn.
|
|
|
|
|
*/
|
|
|
|
|
protected boolean shouldDrawDivider(int position, @Nullable RecyclerView.Adapter<?> adapter) {
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|