a53b3983bf
PiperOrigin-RevId: 210155157 Change-Id: I707512aab6ac57aaebb93275669ae16b92b0e66d
228 lines
8.6 KiB
Java
228 lines
8.6 KiB
Java
/*
|
|
* Copyright (C) 2015 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.android.setupwizardlib;
|
|
|
|
import android.content.Context;
|
|
import android.content.res.TypedArray;
|
|
import android.graphics.Canvas;
|
|
import android.graphics.Rect;
|
|
import android.graphics.drawable.Drawable;
|
|
import androidx.annotation.IntDef;
|
|
import androidx.core.view.ViewCompat;
|
|
import androidx.recyclerview.widget.RecyclerView;
|
|
import android.view.View;
|
|
import java.lang.annotation.Retention;
|
|
import java.lang.annotation.RetentionPolicy;
|
|
|
|
/**
|
|
* An {@link androidx.recyclerview.widget.RecyclerView.ItemDecoration} for RecyclerView to draw
|
|
* dividers between items. This ItemDecoration will draw the drawable specified by {@link
|
|
* #setDivider(android.graphics.drawable.Drawable)} as the divider in between each item by default,
|
|
* and the behavior of whether the divider is shown can be customized by subclassing {@link
|
|
* com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}.
|
|
*
|
|
* <p>Modified from v14 PreferenceFragment.DividerDecoration.
|
|
*/
|
|
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
|
|
|
|
/* static section */
|
|
|
|
/**
|
|
* An interface to be implemented by a {@link RecyclerView.ViewHolder} which controls whether
|
|
* dividers should be shown above and below that item.
|
|
*/
|
|
public interface DividedViewHolder {
|
|
|
|
/**
|
|
* Returns whether divider is allowed above this item. A divider will be shown only if both
|
|
* items immediately above and below it allows this divider.
|
|
*/
|
|
boolean isDividerAllowedAbove();
|
|
|
|
/**
|
|
* Returns whether divider is allowed below this item. A divider will be shown only if both
|
|
* items immediately above and below it allows this divider.
|
|
*/
|
|
boolean isDividerAllowedBelow();
|
|
}
|
|
|
|
@Retention(RetentionPolicy.SOURCE)
|
|
@IntDef({DIVIDER_CONDITION_EITHER, DIVIDER_CONDITION_BOTH})
|
|
public @interface DividerCondition {}
|
|
|
|
public static final int DIVIDER_CONDITION_EITHER = 0;
|
|
public static final int DIVIDER_CONDITION_BOTH = 1;
|
|
|
|
/** @deprecated Use {@link #DividerItemDecoration(android.content.Context)} */
|
|
@Deprecated
|
|
public static DividerItemDecoration getDefault(Context context) {
|
|
return new DividerItemDecoration(context);
|
|
}
|
|
|
|
/* non-static section */
|
|
|
|
private Drawable divider;
|
|
private int dividerHeight;
|
|
private int dividerIntrinsicHeight;
|
|
@DividerCondition private int dividerCondition;
|
|
|
|
public DividerItemDecoration() {}
|
|
|
|
public DividerItemDecoration(Context context) {
|
|
final TypedArray a = context.obtainStyledAttributes(R.styleable.SuwDividerItemDecoration);
|
|
final Drawable divider =
|
|
a.getDrawable(R.styleable.SuwDividerItemDecoration_android_listDivider);
|
|
final int dividerHeight =
|
|
a.getDimensionPixelSize(R.styleable.SuwDividerItemDecoration_android_dividerHeight, 0);
|
|
@DividerCondition
|
|
final int dividerCondition =
|
|
a.getInt(
|
|
R.styleable.SuwDividerItemDecoration_suwDividerCondition, DIVIDER_CONDITION_EITHER);
|
|
a.recycle();
|
|
|
|
setDivider(divider);
|
|
setDividerHeight(dividerHeight);
|
|
setDividerCondition(dividerCondition);
|
|
}
|
|
|
|
@Override
|
|
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
|
|
if (divider == null) {
|
|
return;
|
|
}
|
|
final int childCount = parent.getChildCount();
|
|
final int width = parent.getWidth();
|
|
final int dividerHeight = this.dividerHeight != 0 ? this.dividerHeight : dividerIntrinsicHeight;
|
|
for (int childViewIndex = 0; childViewIndex < childCount; childViewIndex++) {
|
|
final View view = parent.getChildAt(childViewIndex);
|
|
if (shouldDrawDividerBelow(view, parent)) {
|
|
final int top = (int) ViewCompat.getY(view) + view.getHeight();
|
|
divider.setBounds(0, top, width, top + dividerHeight);
|
|
divider.draw(c);
|
|
}
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void getItemOffsets(
|
|
Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
|
|
if (shouldDrawDividerBelow(view, parent)) {
|
|
outRect.bottom = dividerHeight != 0 ? dividerHeight : dividerIntrinsicHeight;
|
|
}
|
|
}
|
|
|
|
private boolean shouldDrawDividerBelow(View view, RecyclerView parent) {
|
|
final RecyclerView.ViewHolder holder = parent.getChildViewHolder(view);
|
|
final int index = holder.getLayoutPosition();
|
|
final int lastItemIndex = parent.getAdapter().getItemCount() - 1;
|
|
if (isDividerAllowedBelow(holder)) {
|
|
if (dividerCondition == DIVIDER_CONDITION_EITHER) {
|
|
// Draw the divider without consulting the next item if we only
|
|
// need permission for either above or below.
|
|
return true;
|
|
}
|
|
} else if (dividerCondition == DIVIDER_CONDITION_BOTH || index == lastItemIndex) {
|
|
// Don't draw if the current view holder doesn't allow drawing below
|
|
// and the current theme requires permission for both the item below and above.
|
|
// Also, if this is the last item, there is no item below to ask permission
|
|
// for whether to draw a divider above, so don't draw it.
|
|
return false;
|
|
}
|
|
// Require permission from index below to draw the divider.
|
|
if (index < lastItemIndex) {
|
|
final RecyclerView.ViewHolder nextHolder = parent.findViewHolderForLayoutPosition(index + 1);
|
|
if (!isDividerAllowedAbove(nextHolder)) {
|
|
// Don't draw if the next view holder doesn't allow drawing above
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
* Whether a divider is allowed above the view holder. The allowed values will be combined
|
|
* according to {@link #getDividerCondition()}. The default implementation delegates to {@link
|
|
* com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows the
|
|
* divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can override
|
|
* this to give more information to decide whether a divider should be drawn.
|
|
*
|
|
* @return True if divider is allowed above this view holder.
|
|
*/
|
|
protected boolean isDividerAllowedAbove(RecyclerView.ViewHolder viewHolder) {
|
|
return !(viewHolder instanceof DividedViewHolder)
|
|
|| ((DividedViewHolder) viewHolder).isDividerAllowedAbove();
|
|
}
|
|
|
|
/**
|
|
* Whether a divider is allowed below the view holder. The allowed values will be combined
|
|
* according to {@link #getDividerCondition()}. The default implementation delegates to {@link
|
|
* com.android.setupwizardlib.DividerItemDecoration.DividedViewHolder}, or simply allows the
|
|
* divider if the view holder doesn't implement {@code DividedViewHolder}. Subclasses can override
|
|
* this to give more information to decide whether a divider should be drawn.
|
|
*
|
|
* @return True if divider is allowed below this view holder.
|
|
*/
|
|
protected boolean isDividerAllowedBelow(RecyclerView.ViewHolder viewHolder) {
|
|
return !(viewHolder instanceof DividedViewHolder)
|
|
|| ((DividedViewHolder) viewHolder).isDividerAllowedBelow();
|
|
}
|
|
|
|
/** Sets the drawable to be used as the divider. */
|
|
public void setDivider(Drawable divider) {
|
|
if (divider != null) {
|
|
dividerIntrinsicHeight = divider.getIntrinsicHeight();
|
|
} else {
|
|
dividerIntrinsicHeight = 0;
|
|
}
|
|
this.divider = divider;
|
|
}
|
|
|
|
/** Gets the drawable currently used as the divider. */
|
|
public Drawable getDivider() {
|
|
return divider;
|
|
}
|
|
|
|
/** Sets the divider height, in pixels. */
|
|
public void setDividerHeight(int dividerHeight) {
|
|
this.dividerHeight = dividerHeight;
|
|
}
|
|
|
|
/** Gets the divider height, in pixels. */
|
|
public int getDividerHeight() {
|
|
return dividerHeight;
|
|
}
|
|
|
|
/**
|
|
* Sets whether the divider needs permission from both the item view holder below and above from
|
|
* where the divider would draw itself or just needs permission from one or the other before
|
|
* drawing itself.
|
|
*/
|
|
public void setDividerCondition(@DividerCondition int dividerCondition) {
|
|
this.dividerCondition = dividerCondition;
|
|
}
|
|
|
|
/**
|
|
* Gets whether the divider needs permission from both the item view holder below and above from
|
|
* where the divider would draw itself or just needs permission from one or the other before
|
|
* drawing itself.
|
|
*/
|
|
@DividerCondition
|
|
public int getDividerCondition() {
|
|
return dividerCondition;
|
|
}
|
|
}
|