SetupWizardLibrary/library/recyclerview/src/com/android/setupwizardlib/DividerItemDecoration.java
Aurimas Liutikas 4860e4ee48 Migrate setup-wizard-lib to androidx.
Test: make setup-wizard-lib
Bug: 76692459
Change-Id: I40171e973d442b1a1815e9e7d7c2cc984cb38bac
2018-04-18 17:26:19 -07:00

244 lines
9.3 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 android.view.View;
import androidx.annotation.IntDef;
import androidx.core.view.ViewCompat;
import androidx.recyclerview.widget.RecyclerView;
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 mDivider;
private int mDividerHeight;
private int mDividerIntrinsicHeight;
@DividerCondition
private int mDividerCondition;
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 (mDivider == null) {
return;
}
final int childCount = parent.getChildCount();
final int width = parent.getWidth();
final int dividerHeight = mDividerHeight != 0 ? mDividerHeight : mDividerIntrinsicHeight;
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();
mDivider.setBounds(0, top, width, top + dividerHeight);
mDivider.draw(c);
}
}
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
if (shouldDrawDividerBelow(view, parent)) {
outRect.bottom = mDividerHeight != 0 ? mDividerHeight : mDividerIntrinsicHeight;
}
}
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 (mDividerCondition == 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 (mDividerCondition == 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) {
mDividerIntrinsicHeight = divider.getIntrinsicHeight();
} else {
mDividerIntrinsicHeight = 0;
}
mDivider = divider;
}
/**
* Gets the drawable currently used as the divider.
*/
public Drawable getDivider() {
return mDivider;
}
/**
* Sets the divider height, in pixels.
*/
public void setDividerHeight(int dividerHeight) {
mDividerHeight = dividerHeight;
}
/**
* Gets the divider height, in pixels.
*/
public int getDividerHeight() {
return mDividerHeight;
}
/**
* 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) {
mDividerCondition = 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 mDividerCondition;
}
}