最近,我使用具有多种视图类型的RecyclerView和PagedListAdapter遇到了各种各样的问题。使用不同视图类型的原因实质上是添加节标题。切换到使用ItemDecoration似乎更稳定,而且模式也更好。
所以我想我将对另一个RecyclerView做同样的事情,试图消除多种视图类型,因此RecyclerView中的每一行都对应于基础PagedList中的一项。问题是,这不是一个简单的节标题TextView。这是CardView。
正确设置宽度有些麻烦(此CardView应该是MATCH_PARENT)。我想我已经知道了,但是还有另一个问题。 CardView正在绘制,但没有背景阴影。我从Why is my cardview not being drawn onto canvas?之类的StackOverflow问题中看到,其他人也有同样的问题。似乎没有使用常规的布局/测量/绘制功能绘制高程阴影。
如何在ItemDecoration中获得CardView阴影?有办法吗?
这是我目前拥有的:
class CardItemDecoration(val adapter: ReservationAdapter) : RecyclerView.ItemDecoration() {
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
super.getItemOffsets(outRect, view, parent, state)
val position = parent.getChildAdapterPosition(view)
if (adapter.hasCard && position == 0) {
outRect.top = getcardView(parent.context, parent).measuredHeight
}
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
val left = parent.paddingLeft
val right = parent.width - parent.paddingRight
if (adapter.hascard && parent.childCount > 0) {
val child = parent.getChildAt(0)
val layout = getCardView(parent.context, parent)
// Draw in the space made by getItemOffsets()
layout.layout(left, 0, right, layout.measuredHeight)
c.save()
// Adjust Y coordinates, as they'll be different for each row
val top = child.top - layout.measuredHeight
c.translate(0f, top.toFloat())
layout.draw(c)
c.restore()
}
}
private lateinit var cardView: ViewGroup
private fun getCardView(context: Context, parent: RecyclerView): View {
if (!::cardView.isInitialized) {
cardView = LinearLayout(context)
LayoutInflater.from(context).inflate(R.layout.call_out_bis_profile, cardView, true)
cardView.apply {
findViewById<TextView>(R.id.infoTextView).text = context.getString(R.string.card_description)
}
val width = parent.width - parent.paddingLeft - parent.paddingRight
cardView.measure(View.MeasureSpec.makeMeasureSpec(width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED))
}
return cardView
}
}
答案 0 :(得分:1)
这是卡片视图装饰示例。这是我的参考:https://github.com/bleeding182/recyclerviewItemDecorations
Paint mPaint;
static RoundRectHelper sRoundRectHelper;
Paint mCornerShadowPaint;
Paint mEdgeShadowPaint;
final RectF mPreShadowBounds;
float mCornerRadius;
Path mCornerShadowPath;
float mShadowSize;
private boolean mDirty = true;
private final int mShadowStartColor;
private final int mShadowEndColor;
private float mPadding;
public CardViewDecoration(Resources resources, int backgroundColor, float radius) {
mShadowStartColor = resources.getColor(R.color.cardview_shadow_start_color);
mShadowEndColor = resources.getColor(R.color.cardview_shadow_end_color);
mShadowSize = resources.getDimension(R.dimen.cardview_shadow_size) * SHADOW_MULTIPLIER;
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mPaint.setColor(backgroundColor);
mCornerShadowPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.DITHER_FLAG);
mCornerShadowPaint.setStyle(Paint.Style.FILL);
mCornerShadowPaint.setDither(true);
mCornerRadius = radius;
mPreShadowBounds = new RectF();
mEdgeShadowPaint = new Paint(mCornerShadowPaint);
buildShadowCorners();
}
@Override
public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) {
Rect bounds = new Rect();
float edgeShadowTop = -mCornerRadius - mShadowSize;
RecyclerView.LayoutManager lm = parent.getLayoutManager();
float size16dp = 16f;
int padding16dp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size16dp, parent.getContext().getResources().getDisplayMetrics());
for (int i = 0; i < parent.getChildCount(); i++) {
int save = c.save();
// using decorated values, remove what we set before
View child = parent.getChildAt(i);
bounds.set(lm.getDecoratedLeft(child) + padding16dp - (int) mPadding,
lm.getDecoratedTop(child),
lm.getDecoratedRight(child) - padding16dp + (int) mPadding,
lm.getDecoratedBottom(child));
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int position = params.getViewAdapterPosition();
int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderItemTestAdapter.HEADER) {
bounds.top = (int) (bounds.top + padding16dp - mPadding);
// LT
c.translate(bounds.left + mCornerRadius, bounds.top + mCornerRadius);
c.drawPath(mCornerShadowPath, mCornerShadowPaint);
c.drawRect(0, edgeShadowTop, bounds.width() - 2 * mCornerRadius, -mCornerRadius, mEdgeShadowPaint);
// RT
c.rotate(90f);
c.translate(0, -bounds.width() + 2 * mCornerRadius);
c.drawPath(mCornerShadowPath, mCornerShadowPaint);
c.drawRect(0, edgeShadowTop, bounds.height() - mCornerRadius, -mCornerRadius, mEdgeShadowPaint);
// LBorder
c.rotate(180f);
c.translate(-bounds.height(), -bounds.width() + 2 * mCornerRadius);
c.drawRect(mCornerRadius, edgeShadowTop, bounds.height(), -mCornerRadius, mEdgeShadowPaint);
} else {
if (parent.getAdapter().getItemViewType(position + 1) == HeaderItemTestAdapter.HEADER) {
bounds.bottom = (int) (bounds.bottom - padding16dp + mPadding);
// last item before next header
c.rotate(180f);
c.translate(-bounds.left - bounds.width() + mCornerRadius, -bounds.top - bounds.height() + mCornerRadius);
c.drawPath(mCornerShadowPath, mCornerShadowPaint);
c.drawRect(0, edgeShadowTop, bounds.width() - 2 * mCornerRadius, -mCornerRadius, mEdgeShadowPaint);
// RT / Right border
c.rotate(90f);
c.translate(0, -bounds.width() + 2 * mCornerRadius);
c.drawPath(mCornerShadowPath, mCornerShadowPaint);
c.drawRect(0, edgeShadowTop, bounds.height() - mCornerRadius, -mCornerRadius, mEdgeShadowPaint);
// Left border
c.rotate(180f);
c.translate(-bounds.height(), -bounds.width() + 2 * mCornerRadius);
c.drawRect(mCornerRadius, edgeShadowTop, bounds.height(), -mCornerRadius, mEdgeShadowPaint);
} else {
// Right border
c.translate(bounds.left, bounds.top);
c.rotate(90f);
c.translate(0, -bounds.width() + mCornerRadius);
c.drawRect(0, edgeShadowTop, bounds.height(), -mCornerRadius, mEdgeShadowPaint);
// Left border
c.rotate(180f);
c.translate(-bounds.height(), -bounds.width() + 2 * mCornerRadius);
c.drawRect(0, edgeShadowTop, bounds.height(), -mCornerRadius, mEdgeShadowPaint);
}
}
c.restoreToCount(save);
}
}
private void buildShadowCorners() {
mPadding = 0f;
RectF innerBounds = new RectF(-mCornerRadius, -mCornerRadius, mCornerRadius, mCornerRadius);
RectF outerBounds = new RectF(innerBounds);
outerBounds.inset(-mShadowSize, -mShadowSize);
if (mCornerShadowPath == null) {
mCornerShadowPath = new Path();
} else {
mCornerShadowPath.reset();
}
mCornerShadowPath.setFillType(Path.FillType.EVEN_ODD);
mCornerShadowPath.moveTo(-mCornerRadius, 0);
mCornerShadowPath.rLineTo(-mShadowSize, 0);
// outer arc
mCornerShadowPath.arcTo(outerBounds, 180f, 90f, false);
// inner arc
mCornerShadowPath.arcTo(innerBounds, 270f, -90f, false);
mCornerShadowPath.close();
float startRatio = mCornerRadius / (mCornerRadius + mShadowSize);
mCornerShadowPaint.setShader(new RadialGradient(0, 0, mCornerRadius + mShadowSize, new int[]{
mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[]{0f, startRatio, 1f},
Shader.TileMode.CLAMP));
// we offset the content shadowSize/2 pixels up to make it more realistic.
// this is why edge shadow shader has some extra space
// When drawing bottom edge shadow, we use that extra space.
mEdgeShadowPaint.setShader(new LinearGradient(0, -mCornerRadius + mShadowSize, 0, -mCornerRadius - mShadowSize,
new int[]{mShadowStartColor, mShadowStartColor, mShadowEndColor}, new float[]{0f, .5f, 1f},
Shader.TileMode.CLAMP));
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
super.getItemOffsets(outRect, view, parent, state);
Resources resources = parent.getContext().getResources();
float size16dp = 16f;
int padding16dp = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, size16dp, resources.getDisplayMetrics());
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
int position = params.getViewAdapterPosition();
int viewType = parent.getAdapter().getItemViewType(position);
if (viewType == HeaderItemTestAdapter.HEADER) {
// header
outRect.set(0, (int) (padding16dp), 0, 0);
} else {
if (parent.getAdapter().getItemViewType(position + 1) == HeaderItemTestAdapter.HEADER) {
// last item before next header
outRect.set(0, 0, 0, (int) (padding16dp));
}
}
outRect.left = (int) padding16dp;
outRect.right = (int) padding16dp;
}
}
这真的对我有帮助!