首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在回收器视图中删除动画时如何隐藏分隔符

在回收器视图中删除动画时如何隐藏分隔符
EN

Stack Overflow用户
提问于 2016-04-12 14:59:46
回答 3查看 5.7K关注 0票数 26

默认情况下,RecyclerView会附带一个很好的删除动画,只要您setHasStableIds(true)并在getItemId上提供正确的实现。

最近,我通过RecyclerView通过https://stackoverflow.com/a/27037230/72437添加了除法器。

结果如下

0w

https://youtu.be/c81OsFAL3zY (在播放删除动画时,为了使分隔符更加可见,我临时将RecyclerView背景更改为红色)

当播放删除动画时,分隔符仍然是可见的。

但是,如果我查看GMail示例,在播放删除动画时,分隔线将不再可见。他们被覆盖在一个坚实的颜色区域。

https://www.youtube.com/watch?v=cLs7paU-BIg

我想知道,在播放删除动画时,如何通过不显示分隔线来实现与GMail相同的效果?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-04-15 16:36:47

解决办法相当容易。要对装饰进行动画化,您可以而且应该使用view.getTranslation_()view.getAlpha()。不久前,我写了一篇关于这个问题的博客文章,你可以读到这里

翻译与褪色

默认的布局管理器将淡出视图(alpha),并在添加或删除视图时对其进行转换。你必须在你的装饰中说明这一点。

这个想法很简单:

无论您如何绘制装饰,请使用view.getAlpha()view.getTranslationY()将相同的alpha和转换应用于绘图。

按照你的联系答案,它必须修改如下:

代码语言:javascript
运行
复制
// 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);

完整的样本

我喜欢自己画东西,因为我认为画一条线比布置一个可绘制的线要低得多,所以如下所示:

代码语言:javascript
运行
复制
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);
            }
        }
    }
}
票数 35
EN

Stack Overflow用户

发布于 2016-04-15 12:01:34

首先,很抱歉有这么大的答案。但是,我觉得有必要包括我的整个测试活动,这样您就可以看到我做了什么。

问题

您遇到的问题是,DividerItemDecoration不知道您的行的状态。它不知道该项目是否被删除。

出于这个原因,我创建了一个波霍,我们可以使用它来包含一个整数(我们使用它作为一个itemId和一个可视表示,以及一个布尔值,表示该行是否被删除)。

当您决定删除条目(在本例中为adapter.notifyItemRangeRemoved(3, 8);)时,还必须将关联的Pojo设置为被删除(在本例中为pojo.beingDeleted = true;)。

当beingDeleted被重置为父视图的颜色时,分隔符的位置。为了掩盖隔板。

我不太喜欢使用dataset本身来管理其父列表的状态。也许还有更好的办法。

结果可视化

活动:

代码语言:javascript
运行
复制
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;
        }
    }
}

活动布局

代码语言:javascript
运行
复制
<?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“行”布局

代码语言:javascript
运行
复制
<?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>
票数 7
EN

Stack Overflow用户

发布于 2016-04-21 04:44:34

我认为,当执行要删除的滑动时,您用来在每一行之后绘制一个分隔符的ItemDecorator会把事情搞砸。

与使用ItemDecorator在回收视图中绘制除法器不同,在recyclerview子布局的末尾添加一个视图design.which将绘制一条类似于ItemDecorator的分隔线。

代码语言:javascript
运行
复制
<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>
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/36577042

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档