blob: d757f053632a2b9ec69fe7db90b54e1807960c52 [file] [log] [blame]
/*
* Copyright (C) 2019 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.car.ui.recyclerview.decorations.linear;
import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.view.View;
import androidx.annotation.IntDef;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import java.lang.annotation.Retention;
/**
* Adds an offset to the start of a RecyclerView using a LinearLayoutManager or its subclass.
*
* <p>If the RecyclerView.LayoutManager is oriented vertically, the offset will be added to the top
* of the RecyclerView. If the LayoutManager is oriented horizontally, the offset will be added to
* the left of the RecyclerView.
*/
public class LinearOffsetItemDecoration extends RecyclerView.ItemDecoration {
private int mOffsetPx;
private Drawable mOffsetDrawable;
private int mOrientation;
@OffsetPosition
private int mOffsetPosition;
/** The possible values for setScrollbarPosition. */
@IntDef({
OffsetPosition.START,
OffsetPosition.END,
})
@Retention(SOURCE)
public @interface OffsetPosition {
/** Position the offset to the start of the screen. */
int START = 0;
/** Position offset to the end of the screen. */
int END = 1;
}
/**
* Constructor that takes in the size of the offset to be added to the start of the
* RecyclerView.
*
* @param offsetPx The size of the offset to be added to the start of the RecyclerView in pixels
* @param offsetPosition Position where offset needs to be applied.
*/
public LinearOffsetItemDecoration(int offsetPx, int offsetPosition) {
this.mOffsetPx = offsetPx;
this.mOffsetPosition = offsetPosition;
}
/**
* Constructor that takes in a {@link Drawable} to be drawn at the start of the RecyclerView.
*
* @param offsetDrawable The {@code Drawable} to be added to the start of the RecyclerView
*/
public LinearOffsetItemDecoration(Drawable offsetDrawable) {
this.mOffsetDrawable = offsetDrawable;
}
/**
* Determines the size and location of the offset to be added to the start of the RecyclerView.
*
* @param outRect The {@link Rect} of offsets to be added around the child view
* @param view The child view to be decorated with an offset
* @param parent The RecyclerView onto which dividers are being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void getItemOffsets(
Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
if (mOffsetPosition == OffsetPosition.START && parent.getChildAdapterPosition(view) > 0) {
return;
}
int itemCount = state.getItemCount();
if (mOffsetPosition == OffsetPosition.END
&& parent.getChildAdapterPosition(view) != itemCount - 1) {
return;
}
mOrientation = ((LinearLayoutManager) parent.getLayoutManager()).getOrientation();
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
if (mOffsetPx > 0) {
if (mOffsetPosition == OffsetPosition.START) {
outRect.left = mOffsetPx;
} else {
outRect.right = mOffsetPx;
}
} else if (mOffsetDrawable != null) {
if (mOffsetPosition == OffsetPosition.START) {
outRect.left = mOffsetDrawable.getIntrinsicWidth();
} else {
outRect.right = mOffsetDrawable.getIntrinsicWidth();
}
}
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
if (mOffsetPx > 0) {
if (mOffsetPosition == OffsetPosition.START) {
outRect.top = mOffsetPx;
} else {
outRect.bottom = mOffsetPx;
}
} else if (mOffsetDrawable != null) {
if (mOffsetPosition == OffsetPosition.START) {
outRect.top = mOffsetDrawable.getIntrinsicHeight();
} else {
outRect.bottom = mOffsetDrawable.getIntrinsicHeight();
}
}
}
}
/**
* Draws horizontal or vertical offset onto the start of the parent RecyclerView.
*
* @param c The {@link Canvas} onto which an offset will be drawn
* @param parent The RecyclerView onto which an offset is being added
* @param state The current RecyclerView.State of the RecyclerView
*/
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
super.onDraw(c, parent, state);
if (mOffsetDrawable == null) {
return;
}
if (mOrientation == LinearLayoutManager.HORIZONTAL) {
drawOffsetHorizontal(c, parent);
} else if (mOrientation == LinearLayoutManager.VERTICAL) {
drawOffsetVertical(c, parent);
}
}
private void drawOffsetHorizontal(Canvas canvas, RecyclerView parent) {
int parentTop = parent.getPaddingTop();
int parentBottom = parent.getHeight() - parent.getPaddingBottom();
int parentLeft = 0;
int offsetDrawableRight = 0;
if (mOffsetPosition == OffsetPosition.START) {
parentLeft = parent.getPaddingLeft();
offsetDrawableRight = parentLeft + mOffsetDrawable.getIntrinsicWidth();
} else {
View lastChild = parent.getChildAt(parent.getChildCount() - 1);
RecyclerView.LayoutParams lastChildLayoutParams =
(RecyclerView.LayoutParams) lastChild.getLayoutParams();
parentLeft = lastChild.getRight() + lastChildLayoutParams.rightMargin;
offsetDrawableRight = parentLeft + mOffsetDrawable.getIntrinsicWidth();
}
mOffsetDrawable.setBounds(parentLeft, parentTop, offsetDrawableRight, parentBottom);
mOffsetDrawable.draw(canvas);
}
private void drawOffsetVertical(Canvas canvas, RecyclerView parent) {
int parentLeft = parent.getPaddingLeft();
int parentRight = parent.getWidth() - parent.getPaddingRight();
int parentTop = 0;
int offsetDrawableBottom = 0;
if (mOffsetPosition == OffsetPosition.START) {
parentTop = parent.getPaddingTop();
offsetDrawableBottom = parentTop + mOffsetDrawable.getIntrinsicHeight();
} else {
View lastChild = parent.getChildAt(parent.getChildCount() - 1);
RecyclerView.LayoutParams lastChildLayoutParams =
(RecyclerView.LayoutParams) lastChild.getLayoutParams();
parentTop = lastChild.getBottom() + lastChildLayoutParams.bottomMargin;
offsetDrawableBottom = parentTop + mOffsetDrawable.getIntrinsicHeight();
}
mOffsetDrawable.setBounds(parentLeft, parentTop, parentRight, offsetDrawableBottom);
mOffsetDrawable.draw(canvas);
}
}