GVKun编程网logo

android – RecyclerView – NotifyItemInsert上没有动画(android recyclerview动态添加item)

11

本文将介绍android–RecyclerView–NotifyItemInsert上没有动画的详细情况,特别是关于androidrecyclerview动态添加item的相关信息。我们将通过案例分析

本文将介绍android – RecyclerView – NotifyItemInsert上没有动画的详细情况,特别是关于android recyclerview动态添加item的相关信息。我们将通过案例分析、数据研究等多种方式,帮助您更全面地了解这个主题,同时也将涉及一些关于Android MotionLayout + Recyclerview,recyclerview中的视图不可单击、Android RecyclerView ItemDecoration 类解析、android RecyclerView ItemDecoration 详解、Android RecyclerView 更新子项目 notifyItemChanged的知识。

本文目录一览:

android – RecyclerView – NotifyItemInsert上没有动画(android recyclerview动态添加item)

android – RecyclerView – NotifyItemInsert上没有动画(android recyclerview动态添加item)

出于某种原因,当向RecyclerView添加新项目时(应插入列表顶部),除非我向下滚动列表并返回到顶部,并且没有任何动画,否则它将不会显示. (只是出现在列表的顶部,好像它一直在那里).使用正确的动画删除项目可以正常工作.

RecyclerViewAdapter:

@Override
public void onNewDatabaseEntryAdded() {
    //item added to top of the list
    notifyItemInserted(0);
}

public FileViewerAdapter(Context context) {
    super();
    mContext = context;
    mDatabase = new DBHelper(mContext);
    mDatabase.setonDatabaseChangedListener(this);
}

sqlite数据库:

private static OnDatabaseChangedListener mOnDatabaseChangedListener;

public static void setonDatabaseChangedListener(OnDatabaseChangedListener listener) {
    mOnDatabaseChangedListener = listener;
}

public long addRecording(String recordingName,String filePath,long length) {

    sqliteDatabase db = getWritableDatabase();
    ContentValues cv = new ContentValues();
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_NAME,recordingName);
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_FILE_PATH,filePath);
    cv.put(DBHelperItem.COLUMN_NAME_RECORDING_LENGTH,length);
    cv.put(DBHelperItem.COLUMN_NAME_TIME_ADDED,System.currentTimeMillis());
    long rowId = db.insert(DBHelperItem.TABLE_NAME,null,cv);

    if (mOnDatabaseChangedListener != null) {
        mOnDatabaseChangedListener.onNewDatabaseEntryAdded();
    }

    return rowId;
}

监听器:

public interface OnDatabaseChangedListener{
    void onNewDatabaseEntryAdded();
    void onDatabaseEntryRenamed();
}

编辑:

我应该提一下,如果我使用NotifyDataSetChanged而不是NotifyItemInserted,那么新项目会立即显示,但RecyclerView不会滚动到列表的顶部. (手动必须向上滚动才能看到它).

解决方法

发生这种情况是因为linearlayoutmanager认为该项目是插入第一项之上的.当您不在列表的顶部时,此行为是有意义的,但我知道当您位于列表顶部时,它是不直观的.我们可能会更改此行为,同时,如果linearlayoutmanager.findFirstCompletelyVisibleItemPosition()返回0,则可以在插入项后调用linearlayoutmanager.scrollToPosition(0).

Android MotionLayout + Recyclerview,recyclerview中的视图不可单击

Android MotionLayout + Recyclerview,recyclerview中的视图不可单击

好的,我已经解决了这个错误。该错误来自recyclerview和motionlayot之间的兼容性。只需将您的recyclerview版本设置为最新版本即可。

Android RecyclerView ItemDecoration 类解析

Android RecyclerView ItemDecoration 类解析

一、前言

<font face = 黑体>毫无疑问,RecyclerView 是 Android 中最重要的系统组件之一,它的出现就是为了高效代替 ListView 和 GridView。

<font face = 黑体>今天,我们来讲讲 RecyclerView 中的静态内部类 ItemDecoration。顾名思义 ItemDecoration 就是 Item 的装饰,我们可以在 Item 的上下左右添加自定义的装饰,从而丰富 Item 的 UI 效果。

二、RecyclerView 基础知识

<font face = 黑体>我们都知道 RecyclerView 里面就是一个又一个的 Item,但是其实这些 Item 外面包裹着一个矩形,只是我们再使用 RecyclerView 的时候 Left、Right、Top 和 Bottom 默认都是 0,所以我们看不到这些矩形,具体如下图所示:
RecyclerView

三、DividerItemDecoration(系统提供)

<font face = 黑体>我们都知道,使用 RecyclerView 时 ,我们不能像 ListView 那样通过 setDivider() 的方式来设置分割线,但是系统已经为我们提供了一个 DividerItemDecoration 类来设置分割线,这个类就是继承 RecyclerView.ItemDecoration,我们来看下源码:

public class DividerItemDecoration extends RecyclerView.ItemDecoration {
    public static final int HORIZONTAL = LinearLayout.HORIZONTAL;
    public static final int VERTICAL = LinearLayout.VERTICAL;

    private static final String TAG = "DividerItem";
    private static final int[] ATTRS = new int[]{ android.R.attr.listDivider };
    ... ...
    ... ...

3.1、RecyclerView 简单使用

<font face = 黑体>不设置分割线,效果如下所示:

RecyclerView

3.2、使用 DividerItemDecoration 设置分割线

<font face = 黑体>DividerItemDecoration 的使用非常简单,只需添加下面代码即可:

DividerItemDecoration decoration = new DividerItemDecoration(this,DividerItemDecoration.VERTICAL);
recyclerView.addItemDecoration(decoration);

<font face = 黑体>具体效果如下所示:

在这里插入图片描述
<font face = 黑体>一般情况下以上 RecyclerView 的基本用法便可以实现绝大多数需求,但是某些场景下却远远不够,特别是需要实现比较复杂的 UI 效果的时候,所以这时候就需要利用 ItemDecoration,接下来我们就学习一下 ItemDecoration 的具体使用。

四、ItemDecoration 源码

<font face = 黑体>首先,我们来看一下 ItemDecoration 的源码,这里的源码已经把注释和三个已经被弃用的方法去掉了,具体如下所示:

public abstract static class ItemDecoration {
 
    public void onDraw(@NonNull Canvas c, @NonNull RecyclerView parent, @NonNull State state) {
        onDraw(c, parent);
    }
    
    public void onDrawOver(@NonNull Canvas c, @NonNull RecyclerView parent,  @NonNull State state) {
        onDrawOver(c, parent);
    }

    public void getItemOffsets(@NonNull Rect outRect, @NonNull View view, @NonNull RecyclerView parent, @NonNull State state) {
        getItemOffsets(outRect, ((LayoutParams) view.getLayoutParams()).getViewLayoutPosition(), parent);
    }
}

<font face = 黑体>从源码中我们可以看出 ItemDecoration 类中就只有三个方法,分别是 onDraw()、onDrawOver() 和 getItemOffsets(),具体作用如下:

  • <font face = 黑体>onDraw(): 在子视图上绘制内容,绘制图层在 Item 以下,所以如果绘制区域与 Item 区域相重叠,会被遮挡;
  • <font face = 黑体>onDrawOver():同样是绘制内容,但与onDraw() 的区别是,绘制图层在最上层;
  • <font face = 黑体>getItemOffsets():设置ItemView的内嵌偏移长度。

4.1、getItemOffsets()

<font face = 黑体>getItemOffsets() 的作用就是设置 Item 的内嵌偏移长度,从上面我们已经知道,RecyclerView 的 Item 外面是包裹着一个矩形的,这个方法就是用来设置矩形与 Item 之间的间隔的。

<font face = 黑体>具体使用:

public class RectItemDecoration extends RecyclerView.ItemDecoration {

    // 参数说明:
    // 1. outRect:全为 0 的 Rect(包括着Item)
    // 2. view:RecyclerView 中的 视图 Item
    // 3. parent:RecyclerView 本身
    // 4. state:状态
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        // 4个参数分别对应左(Left)、上(Top)、右(Right)、下(Bottom)
        // 上述语句代表:左、右、上和下偏移长度=100px
        outRect.set(100, 100, 100,100);
    }
}
//用自定义分割线类设置分割线
recyclerView.addItemDecoration(new RectItemDecoration());

<font face = 黑体>效果如下所示:(上下左右都设置了 100px 的偏移量)

getOffSet()

4.2、onDraw()

<font face = 黑体>onDraw() 的作用是通过 Canvas 对象绘制内容,需要注意的是 onDraw() 绘制会先于 Item 的绘制,所以如果在 onDraw() 中绘制的内容在 Item 边界内,就会被 Item 遮挡住,所以 onDraw() 一般会和 getItemOffsets() 结合一起使用,即在矩形与 Item 的间隔区域内绘制内容。

<font face = 黑体>实例1:在左侧间隔区域绘制一个空心圆,并在下侧间隔区域绘制一个 20px 的红色分割线。

<font face = 黑体>我们先来看效果:

在这里插入图片描述
<font face = 黑体>具体代码如下所示:

public class CircleRectDecoration extends RecyclerView.ItemDecoration {

    private Paint colorPaint;
    private Paint dividerPaint;
    
    // 初始化
    public RectItemDecoration() {
        colorPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        colorPaint.setColor(Color.BLUE);
        colorPaint.setStyle(Paint.Style.STROKE);
        colorPaint.setStrokeWidth(5);

        dividerPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
        dividerPaint.setColor(Color.RED);
        dividerPaint.setStyle(Paint.Style.FILL);
    }

    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        outRect.set(100, 0, 0, 20);
    }

    @Override
    public void onDraw(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
        super.onDraw(canvas, parent, state);
        RecyclerView.LayoutManager layoutManager = parent.getLayoutManager();
        // 需要遍历每个 Item 进行绘制
        for (int i = 0; i < parent.getChildCount(); i++) {
            View childView = parent.getChildAt(i);
            int leftItemWidth = layoutManager.getLeftDecorationWidth(childView);
            int bottomItemHeight = layoutManager.getBottomDecorationHeight(childView);
            int left = leftItemWidth / 2;
            canvas.drawCircle(left, childView.getTop() + childView.getHeight() / 2, 20, colorPaint);
            // getItemOffsets() 中的设置的是 bottom = 20px;所以在 drawRect 时,top 为 childView.getBottom, bottom 为top + bottomDecorationHeight
            canvas.drawRect(new Rect(leftItemWidth, childView.getBottom(),
                    childView.getWidth() + leftItemWidth,
                    childView.getBottom() + bottomItemHeight), dividerPaint);
        }
    }

<font face = 黑体>getItemOffsets() 是针对每个 item 都会执行一次,也就是说每个 item 的 outRect 可以设置为不同值,但是 onDraw() 是针对 ItemDecoration 的,不是针对 item 的,只执行一次。所以我们在 onDraw() 中绘制的时候,需要遍历每个 item 进行绘制。

4.2、onDrawOver()

<font face = 黑体>onDrawOver() 的作用与 onDraw() 类似,都是通过 Canvas 对象绘制内容,但与onDraw() 的区别是:onDrawOver() 绘制是后于 onDraw() 的,所以绘制内容是不会被 Item 所遮挡的,反而 Item 会被 onDrawOver() 绘制的内容所遮挡。

<font face = 黑体>实例2:在实例1的基础上,绘制一个角标到 Item 上。

<font face = 黑体>我们先来看效果:

角标
<font face = 黑体>具体代码如下所示:

@Override
public void onDrawOver(@NonNull Canvas canvas, @NonNull RecyclerView parent, @NonNull RecyclerView.State state) {
    super.onDrawOver(canvas, parent, state);

    int childCount = parent.getChildCount();
    for (int i = 0; i < childCount; i++) {
        View view = parent.getChildAt(i);
        int index = parent.getChildAdapterPosition(view);
        float top = view.getTop();
        if (index < 3) {
            canvas.drawBitmap(mIcon, 120, top, flagPaint);
        }
    }
}

五、小结

<font face = 黑体>自定义 ItemDecoration 通常要根据需要,复写它的 3 个方法。

  • <font face = 黑体>getItemOffsets 撑开 Item 上、下、左、右四个方向的空间;
  • <font face = 黑体>onDraw 在 Item 内容之下绘制图形;
  • <font face = 黑体>onDrawOver 在 Item 内容之上绘制图形。

<font face = 黑体>ItemDecoration 的作用远不止以上这么一点,我这里只是简单的介绍了下 ItemDecoration 中三个方法的使用,从而使得 RecyclerView 中的 Item 的 UI 更加丰富。

android RecyclerView ItemDecoration 详解

android RecyclerView ItemDecoration 详解

https://www.cnblogs.com/ldq2016/p/5377605.html

Android RecyclerView 更新子项目 notifyItemChanged

Android RecyclerView 更新子项目 notifyItemChanged

Android RecyclerView 更新子项目 notifyItemChanged

在过去 Android 的 ListView 中,如果 ListView 中某一个或者一批项目发生变化,需要通过 adapter 的 notifyDataSetChanged 更新数据到最新,但是从 ListView 演进到现在的 RecyclerView,数据的更新不需要像 ListView 那样 notifyDataSetChanged,而是要采用 RecyclerView 的 notifyItemChanged,传入一个 pos 位置,通知 RecyclerView 该 pos 位置已经失效,需要重新绘制和 UI 更新。现在给出一个例子,上面一个 Button 按钮,下面一个 RecyclerView:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical">

    <Button
        android:id="@+id/button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="随机更新" />

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

</LinearLayout>


每次点击 Button 按钮,将随机更新某一个位置的时间到最新:

package zhangphil.demo;

import android.app.Activity;
import android.graphics.Color;
import android.os.Bundle;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.Random;


public class MainActivity extends Activity {
    private ArrayList data = new ArrayList();

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        for (int i = 0; i < 5; i++) {
            data.add(System.currentTimeMillis());
        }

        RecyclerView mRecyclerView = findViewById(R.id.recycler_view);

        LinearLayoutManager mLayoutManager = new LinearLayoutManager(this);
        mLayoutManager.setOrientation(LinearLayout.VERTICAL);
        mRecyclerView.setLayoutManager(mLayoutManager);

        final RecyclerView.Adapter mAdapter = new MyAdapter();
        mRecyclerView.setAdapter(mAdapter);

        final Random random = new Random();

        findViewById(R.id.button).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                int pos = random.nextInt(data.size());
                data.set(pos, System.currentTimeMillis());
                mAdapter.notifyItemChanged(pos);

                Toast.makeText(getApplicationContext(), "更新:" + pos + "," + data.get(pos), Toast.LENGTH_LONG).show();
            }
        });
    }


    private class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> {
        public MyAdapter() {
            super();
        }

        @Override
        public ViewHolder onCreateViewHolder(ViewGroup viewGroup, int i) {
            View view = LayoutInflater.from(getApplicationContext()).inflate(android.R.layout.simple_list_item_2, null);
            ViewHolder holder = new ViewHolder(view);
            return holder;
        }

        @Override
        public void onBindViewHolder(ViewHolder viewHolder, int i) {
            viewHolder.text1.setText(i + "");
            viewHolder.text2.setText(data.get(i) + "");
        }

        @Override
        public int getItemCount() {
            return data.size();
        }

        public class ViewHolder extends RecyclerView.ViewHolder {
            public TextView text1;
            public TextView text2;

            public ViewHolder(View itemView) {
                super(itemView);
                text1 = itemView.findViewById(android.R.id.text1);
                text1.setTextColor(Color.RED);
                text2 = itemView.findViewById(android.R.id.text2);
                text2.setTextColor(Color.BLUE);
            }
        }
    }
}


事实上 RecyclerView 的 notifyItemChanged 的底层调用的是 notifyItemRangeChanged:

/**
         * Notify any registered observers that the item at <code>position</code> has changed.
         * Equivalent to calling <code>notifyItemChanged(position, null);</code>.
         *
         * <p>This is an item change event, not a structural change event. It indicates that any
         * reflection of the data at <code>position</code> is out of date and should be updated.
         * The item at <code>position</code> retains the same identity.</p>
         *
         * @param position Position of the item that has changed
         *
         * @see #notifyItemRangeChanged(int, int)
         */
        public final void notifyItemChanged(int position) {
            mObservable.notifyItemRangeChanged(position, 1);
        }

该方法使得 RecyclerView 批量范围内(range)数据更新,notifyItemChanged 巧妙的将第二个参数计数器设置为 1 得以实现。后续再介绍 RecyclerView 的 notifyItemRangeChanged。

关于android – RecyclerView – NotifyItemInsert上没有动画android recyclerview动态添加item的问题我们已经讲解完毕,感谢您的阅读,如果还想了解更多关于Android MotionLayout + Recyclerview,recyclerview中的视图不可单击、Android RecyclerView ItemDecoration 类解析、android RecyclerView ItemDecoration 详解、Android RecyclerView 更新子项目 notifyItemChanged等相关内容,可以在本站寻找。

本文标签: