web-dev-qa-db-ja.com

notifyItemChanged()RecyclerViewをスクロールさせ、UPにジャンプします

サーバーのリストを表示するアダプターを備えたRecycleViewがあり、ユーザーは1つのサーバーを選択する必要があります。

onClick()メソッド内でnotifyItemChanged(previousPosition)を呼び出して、古いサーバーを選択解除し、新しいサーバーを選択すると、RecycleViewリストがリストの真ん中にジャンプします。

この問題は、RecycleViewリスト内の最後の2つまたは3つのサーバーの1つをクリックしたときに発生します

これが私のRecyclerView.Adapterのコードです:

public class ServerAdapter extends RecyclerView.Adapter<ServerAdapter.ServerViewHolder> {

    private List<Server> listServers = new ArrayList<>();
    private int[] icons = new int[]{R.drawable.server1,R.drawable.server2,R.drawable.server3,R.drawable.server4,R.drawable.server5,R.drawable.server6,R.drawable.offline};
    private int selected = 0;
    private int previousSelected = 0;

    public ServerAdapter(List<Server> listServers){
        this.listServers = listServers;
    }

    @Override
    public ServerViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.server_relative_layout,parent,false);
        return new ServerViewHolder(view);
    }

    @Override
    public void onBindViewHolder(final ServerViewHolder holder, final int position) {
        if(position == selected){
            holder.getBackground().setSelected(true);
        }else{
            holder.getBackground().setSelected(false);
        }
        holder.getBackground().setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(position != selected){
                    previousSelected = selected;
                    selected = position;
                    holder.getBackground().setSelected(true);
                    notifyItemChanged(previousSelected);
                }
            }
        });
        holder.getImageServer().setImageResource(icons[position%6]);
        holder.getTextNameServer().setText(listServers.get(position).getName());
        holder.getTextConnected().setText(listServers.get(position).getUrl());
    }

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

    public class ServerViewHolder extends RecyclerView.ViewHolder{
        private ImageView imageServer;
        private TextView textNameServer;
        private TextView textConnected;
        private View background;
        public ServerViewHolder(View itemView) {
            super(itemView);
            imageServer = (ImageView)itemView.findViewById(R.id.imageServer);
            textNameServer = (TextView)itemView.findViewById(R.id.textNameServer);
            textConnected = (TextView)itemView.findViewById(R.id.textConnected);
            background = itemView;
        }

        public ImageView getImageServer() {
            return imageServer;
        }

        public TextView getTextConnected() {
            return textConnected;
        }

        public TextView getTextNameServer() {
            return textNameServer;
        }

        public View getBackground() {
            return background;
        }
    }
}

この問題を解決するための解決策はありますか?ありがとう。

レイアウトの高さを指定し、wrap_contentを許可しないと、問題が発生しました

<Android.support.v7.widget.RecyclerView
    Android:layout_width="wrap_content"
    Android:layout_height="400dp"
    Android:id="@+id/serverRecyclerView"
    Android:layout_margin="10dp"
/>

または私がそのような例のために何かの下にそれを置くとき:

<Android.support.v7.widget.RecyclerView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:id="@+id/serverRecyclerView"
    Android:layout_margin="10dp"
    Android:layout_below="@+id/image"/>

私のコードは正確に:

<Android.support.v7.widget.RecyclerView
    Android:layout_width="wrap_content"
    Android:layout_height="wrap_content"
    Android:id="@+id/serverRecyclerView"
    Android:layout_margin="10dp"
    Android:layout_alignTop="@+id/imageBall"
    Android:layout_alignParentRight="true"
    Android:layout_alignParentEnd="true"
    Android:layout_toRightOf="@+id/camera"
    Android:layout_toEndOf="@+id/camera"/>
12

これはバグのようです: https://code.google.com/p/Android/issues/detail?id=203574

最善の回避策は、RecyclerViewのLinearLayoutManagerのAutoMeasureプロパティをfalseに設定するというBartの答えのようです。

  LinearLayoutManager llm = new LinearLayoutManager(context);
  llm.setAutoMeasureEnabled(false);       
  recyclerView.setLayoutManager(llm);

FixedSizeをtrueソリューションに設定すると、副作用が多すぎます...

RecyclerView.setHasFixedSize(true)

13
Aace

理由はわかりませんが、使用しました:

RecyclerView.setHasFixedSize(true)

これは私のために働いた。お役に立てば幸いです。

4
zzq
 Android:descendantFocusability="blocksDescendants"

Android:descendantFocusability = "blocksDescendants"

この属性は私のバグを解決します

4
Zhe Guo
RecyclerView.ItemAnimator animator = myRecyclerListView.getItemAnimator();
if (animator instanceof SimpleItemAnimator) {
    ((SimpleItemAnimator)animator).setSupportsChangeAnimations(false);
}
1
Ajay George

この問題に遭遇した人は、使用してみてください

yourRecyclerView.notifyItemChanged(int position, Object payload);

これは私のためにトリックをしました。

使用する

setAutoMeasureEnabled(false);

動作しましたが、一部のEdgeの場合、リサイクラービューがおかしな動作をしていました。幸運を!

同様の問題が発生し、上記のすべての解決策を試しましたが、誰も機能しませんでした。チェックボックスの値を「アップロード」する必要があるため、「Payloads」を「notifyItemChanged(position、payloads)」にパディングしていたので、ビューホルダー全体の更新を呼び出さずに「Payloads」内に値を渡していました。このソリューションは、最後のビューを除くリサイクラービューのすべてのビューホルダーで機能しました(おそらくすべての「リサイクル」ビューホルダー、つまり既存のビューを「リサイクル」することで「onBindViewHolder」を思い出す人)。 「notifyItemChanged」の使用は、リサイクラービューしかない場合に機能すると思います。また、この「自動スクロール」の問題は、ネストされたスクロールビューとリサイクラービューによって発生すると思います。

私は「raed」によって公開されたケースだったので、「ScroolView-> RecyclerView-> "n" xRecyclerView」。ビューホルダーにリサイクルビューを含めることができるリサイクルビューを含むscroolviewがあります。

親のScrollViewを削除するのは本当に奇妙な解決策であり、使用できなかったので、RecyclerView内ではなく、「ScrollView」内に「onStopNestedScroll」を設定しました。

個人的には、次のようにして「notifyItemChanged」メソッドを呼び出すコード部分の前にプログラムで使用しました。

msvContainer.onStopNestedScroll(mRecyclerView);

ここで、「msvContainer」はRecyclerViewを含む私のScrollViewであり、「mRecyclerView」はScrollViewに含まれる私のRecyclerViewです。この方法は99%機能しました。これは、初めて「notifyItemChanged」を呼び出すと、ビューがScrollViewに対してのみ上にスクロールするため、RecyclerViewの下にあるScrollView内のボタンが非表示になりますが、RecyclerViewアイテムはスクロールされません。最初の呼び出しの後、「notifyItemChanged」は正しく機能します。

私はその呼び出しを見つけました:

msvContainer.stopNestedScroll();

も動作します。ただし、ネストされたスクロールビューが複数ある場合は、ターゲットビューで最初の方法を使用することをお勧めします。

とにかく、ターゲットビュー、つまり私の場合はRecyclerViewは、このメソッドを呼び出すまでスクロールしないため、ビューホルダーの再更新の重要な部分を使い果たした後、「startNestedScroll」を呼び出す必要があります。ビューホルダーも。

(親スクロールビュー内に複数のリサイクラービューがある場合、最も内側のリサイクラービュー内で「notifyItemChanged」を呼び出す必要がある場合は、すべての親ビューに対して「stopNestedScroll」メソッドを使用します。スクロールクリティカルな部分の後でスクロールを再度アクティブにしました)

これがお役に立てば幸いです。素敵なコーディングをしてください。さようなら

0
Z3R0

NestedScrollViewの親ビューとしてRecyclerViewを使用している場合は、それを削除する必要があります。

0
raed

私は同様の問題に遭遇しました、ただxmlレイアウトファイルの世話をしてください。
RecyclerViewまたはRecyclerViewの親ビューでlayout_belowlayout_aboveまたは他の同様のプロパティを使用しないでください。
LinearLayout weightlayout_marginBottom、またはsthを使用して達成できます
layout_belowまたはその他。

0
ThomsonStan

私のRecyclerViewはConstraintLayout内にあり、そのような問題もあり、RecyclerViewのLayoutManagerのsetAutoMeasureEnabled(false)を呼び出しても問題は修正されませんでした。さらに、このメソッドは28.0.0バージョンで非推奨になりました。私がしたことは、RecyclerViewをRelativeLayoutでラップしたところ、チャームのように機能するようになりました。 bugtracker で述べたように、この「問題」はLinearLayoutの意図された動作であり、修正される予定はありません。したがって、可能であれば、RecyclerViewを次のようにラップするだけです。

<RelativeLayout
    Android:id="@+id/container_messages_list"
    Android:layout_width="match_parent"
    Android:layout_height="0dp"
    Android:background="@drawable/chat_back_pattern"
    app:layout_constraintBottom_toTopOf="@+id/bottom_view"
    app:layout_constraintTop_toBottomOf="@+id/toolbar">

    <Android.support.v7.widget.RecyclerView
        Android:id="@+id/messages_list"
        Android:layout_width="match_parent"
        Android:layout_height="match_parent">
    </Android.support.v7.widget.RecyclerView>
</RelativeLayout>
0