SetupWizardLibrary/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java
Setup Wizard Team a53b3983bf Import updated Android Setup Wizard Library 210155157
PiperOrigin-RevId: 210155157
Change-Id: I707512aab6ac57aaebb93275669ae16b92b0e66d
2018-10-01 20:18:23 -07:00

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;
}
}