默认情况下,RecyclerView
会附带一个很好的删除动画,只要您setHasStableIds(true)
并在getItemId
上提供正确的实现。
最近,我通过RecyclerView
通过https://stackoverflow.com/a/27037230/72437添加了除法器。
结果如下
https://youtu.be/c81OsFAL3zY (在播放删除动画时,为了使分隔符更加可见,我临时将RecyclerView
背景更改为红色)
当播放删除动画时,分隔符仍然是可见的。
但是,如果我查看GMail示例,在播放删除动画时,分隔线将不再可见。他们被覆盖在一个坚实的颜色区域。
https://www.youtube.com/watch?v=cLs7paU-BIg
我想知道,在播放删除动画时,如何通过不显示分隔线来实现与GMail相同的效果?
发布于 2016-04-15 16:36:47
解决办法相当容易。要对装饰进行动画化,您可以而且应该使用view.getTranslation_()
和view.getAlpha()
。不久前,我写了一篇关于这个问题的博客文章,你可以读到这里。
翻译与褪色
默认的布局管理器将淡出视图(alpha),并在添加或删除视图时对其进行转换。你必须在你的装饰中说明这一点。
这个想法很简单:
无论您如何绘制装饰,请使用
view.getAlpha()
和view.getTranslationY()
将相同的alpha和转换应用于绘图。
按照你的联系答案,它必须修改如下:
// translate
int top = child.getBottom() + params.bottomMargin + view.getTranslationY();
int bottom = top + mDivider.getIntrinsicHeight();
// apply alpha
mDivider.setAlpha((int) child.getAlpha() * 255f);
mDivider.setBounds(left + view.getTranslationX(), top,
right + view.getTranslationX(), bottom);
mDivider.draw(c);
完整的样本
我喜欢自己画东西,因为我认为画一条线比布置一个可绘制的线要低得多,所以如下所示:
public class SeparatorDecoration extends RecyclerView.ItemDecoration {
private final Paint mPaint;
private final int mAlpha;
public SeparatorDecoration(@ColorInt int color, float width) {
mPaint = new Paint();
mPaint.setColor(color);
mPaint.setStrokeWidth(width);
mAlpha = mPaint.getAlpha();
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
// we retrieve the position in the list
final int position = params.getViewAdapterPosition();
// add space for the separator to the bottom of every view but the last one
if (position < state.getItemCount()) {
outRect.set(0, 0, 0, (int) mPaint.getStrokeWidth()); // left, top, right, bottom
} else {
outRect.setEmpty(); // 0, 0, 0, 0
}
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
// a line will draw half its size to top and bottom,
// hence the offset to place it correctly
final int offset = (int) (mPaint.getStrokeWidth() / 2);
// this will iterate over every visible view
for (int i = 0; i < parent.getChildCount(); i++) {
final View view = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) view.getLayoutParams();
// get the position
final int position = params.getViewAdapterPosition();
// and finally draw the separator
if (position < state.getItemCount()) {
// apply alpha to support animations
mPaint.setAlpha((int) (view.getAlpha() * mAlpha));
float positionY = view.getBottom() + offset + view.getTranslationY();
// do the drawing
c.drawLine(view.getLeft() + view.getTranslationX(),
positionY,
view.getRight() + view.getTranslationX(),
positionY,
mPaint);
}
}
}
}
发布于 2016-04-15 12:01:34
首先,很抱歉有这么大的答案。但是,我觉得有必要包括我的整个测试活动,这样您就可以看到我做了什么。
问题
您遇到的问题是,DividerItemDecoration
不知道您的行的状态。它不知道该项目是否被删除。
出于这个原因,我创建了一个波霍,我们可以使用它来包含一个整数(我们使用它作为一个itemId和一个可视表示,以及一个布尔值,表示该行是否被删除)。
当您决定删除条目(在本例中为adapter.notifyItemRangeRemoved(3, 8);
)时,还必须将关联的Pojo
设置为被删除(在本例中为pojo.beingDeleted = true;
)。
当beingDeleted被重置为父视图的颜色时,分隔符的位置。为了掩盖隔板。
我不太喜欢使用dataset本身来管理其父列表的状态。也许还有更好的办法。
结果可视化
活动:
public class MainActivity extends AppCompatActivity {
private static final int VERTICAL_ITEM_SPACE = 8;
private List<Pojo> mDataset = new ArrayList<Pojo>();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
for(int i = 0; i < 30; i++) {
mDataset.add(new Pojo(i));
}
final RecyclerView recyclerView = (RecyclerView) findViewById(R.id.recyclerView);
LinearLayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
recyclerView.addItemDecoration(new VerticalSpaceItemDecoration(VERTICAL_ITEM_SPACE));
recyclerView.addItemDecoration(new DividerItemDecoration(this));
RecyclerView.ItemAnimator ia = recyclerView.getItemAnimator();
ia.setRemoveDuration(4000);
final Adapter adapter = new Adapter(mDataset);
recyclerView.setAdapter(adapter);
(new Handler(Looper.getMainLooper())).postDelayed(new Runnable() {
@Override
public void run() {
int index = 0;
Iterator<Pojo> it = mDataset.iterator();
while(it.hasNext()) {
Pojo pojo = it.next();
if(index >= 3 && index <= 10) {
pojo.beingDeleted = true;
it.remove();
}
index++;
}
adapter.notifyItemRangeRemoved(3, 8);
}
}, 2000);
}
public class Adapter extends RecyclerView.Adapter<Holder> {
private List<Pojo> mDataset;
public Adapter(@NonNull final List<Pojo> dataset) {
setHasStableIds(true);
mDataset = dataset;
}
@Override
public Holder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.adapter_cell, parent, false);
return new Holder(view);
}
@Override
public void onBindViewHolder(final Holder holder, final int position) {
final Pojo data = mDataset.get(position);
holder.itemView.setTag(data);
holder.textView.setText("Test "+data.dataItem);
}
@Override
public long getItemId(int position) {
return mDataset.get(position).dataItem;
}
@Override
public int getItemCount() {
return mDataset.size();
}
}
public class Holder extends RecyclerView.ViewHolder {
public TextView textView;
public Holder(View itemView) {
super(itemView);
textView = (TextView) itemView.findViewById(R.id.text);
}
}
public class Pojo {
public int dataItem;
public boolean beingDeleted = false;
public Pojo(int dataItem) {
this.dataItem = dataItem;
}
}
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private final int[] ATTRS = new int[]{android.R.attr.listDivider};
private Paint mOverwritePaint;
private Drawable mDivider;
/**
* Default divider will be used
*/
public DividerItemDecoration(Context context) {
final TypedArray styledAttributes = context.obtainStyledAttributes(ATTRS);
mDivider = styledAttributes.getDrawable(0);
styledAttributes.recycle();
initializePaint();
}
/**
* Custom divider will be used
*/
public DividerItemDecoration(Context context, int resId) {
mDivider = ContextCompat.getDrawable(context, resId);
initializePaint();
}
private void initializePaint() {
mOverwritePaint = new Paint();
mOverwritePaint.setColor(ContextCompat.getColor(MainActivity.this, android.R.color.background_light));
}
@Override
public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {
int left = parent.getPaddingLeft();
int right = parent.getWidth() - parent.getPaddingRight();
int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = parent.getChildAt(i);
RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child.getLayoutParams();
int top = child.getBottom() + params.bottomMargin;
int bottom = top + mDivider.getIntrinsicHeight();
Pojo item = (Pojo) child.getTag();
if(item.beingDeleted) {
c.drawRect(left, top, right, bottom, mOverwritePaint);
} else {
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
}
}
public class VerticalSpaceItemDecoration extends RecyclerView.ItemDecoration {
private final int mVerticalSpaceHeight;
public VerticalSpaceItemDecoration(int mVerticalSpaceHeight) {
this.mVerticalSpaceHeight = mVerticalSpaceHeight;
}
@Override
public void getItemOffsets(Rect outRect, View view, RecyclerView parent,
RecyclerView.State state) {
outRect.bottom = mVerticalSpaceHeight;
}
}
}
活动布局
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
android:paddingBottom="@dimen/activity_vertical_margin"
android:background="@android:color/background_light"
tools:context="test.dae.myapplication.MainActivity">
<android.support.v7.widget.RecyclerView
android:id="@+id/recyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</RelativeLayout>
RecyclerView“行”布局
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/text"
android:padding="8dp">
</TextView>
发布于 2016-04-21 04:44:34
我认为,当执行要删除的滑动时,您用来在每一行之后绘制一个分隔符的ItemDecorator会把事情搞砸。
与使用ItemDecorator在回收视图中绘制除法器不同,在recyclerview子布局的末尾添加一个视图design.which将绘制一条类似于ItemDecorator的分隔线。
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
<!-- child layout Design !-->
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="@android:color/darker_gray"
android:layout_gravity="bottom"
/>
</Linearlayout>
https://stackoverflow.com/questions/36577042
复制相似问题