Recyclerview 绝不滚动到位置

Recyclerview not scrolling to position by no means

我有一个带有 recyclerview 的片段,它没有滚动到 selected 位置。它通过预先 select 前一个保存的项目来工作。它确实 select 它(列表中的项目有单选按钮)但它没有滚动到它应该的那个位置。 我已经尝试了我发现的所有方法,但仍然无法正常工作。

这是我尝试滚动的代码:

//1
mBinding.rvManufacturers.scrollToPosition(position);

//2
new Handler().postDelayed(new Runnable() {
                @Override
                public void run() {
                    mBinding.rvManufacturers.scrollToPosition(adapter.getSelectedItem());
                }
            }, 200);
           
//3
mBinding.rvManufacturers.post(() -> mBinding.rvManufacturers.smoothScrollToPosition(adapter.getSelectedItem()));

//4
linearLayoutManager.scrollToPositionWithOffset(adapter.getSelectedItem(), 20);

xml:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">


    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvManufacturers"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:listitem="@layout/item_choose_node_manufacturer" />


</LinearLayout>

片段:

 @Override
    public void onAttach(@NonNull Context context) {
        super.onAttach(context);

        mActivity = getActivity();

        ((App) mActivity.getApplication()).getAppComponent().inject(this);

        mScreenNavigator = new ScreenNavigator(mActivity, mActivity.getSupportFragmentManager());

        mSettingsViewModel = new ViewModelProvider(mActivity, mViewModelFactory)
                .get(SettingsViewModel.class);
    }


    @Nullable
    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        mBinding = FragmentConfigurationBinding.inflate(inflater, container, false);
        mSettingsViewModel.getSensorConfigurationsLiveData()
        .observe(getViewLifecycleOwner() 
        ,this::observeSensorConfiguration);
        setupView();
        return mBinding.getRoot();
    }

    private void setManufacturersList() {
        manufacturersList = new ArrayList<>();

        manufacturersList.add(new DigManufacturerModel("Ford", 1, TypeOfCar.Manual));
        manufacturersList.add(new ManufacturerModel("Mazda", 2, TypeOfCar.Manual));
        manufacturersList.add(new ManufacturerModel("Ferrari", 3, TypeOfCar.Manual));
        manufacturersList.add(new ManufacturerModel("Renault", 4, TypeOfCar.Manual));
        manufacturersList.add(new ManufacturerModel("Lamborghini", 5, TypeOfCar.Manual));
        manufacturersList.add(new ManufacturerModel("Suzuki", 6, TypeOfCar.Manual));
        manufacturersList.add(new DigManufacturerModel("Ford", 7, TypeOfCar.Automatic));
        manufacturersList.add(new ManufacturerModel("Mazda", 8, TypeOfCar.Automatic));
        manufacturersList.add(new ManufacturerModel("Ferrari", 9, TypeOfCar.Automatic));
        manufacturersList.add(new ManufacturerModel("Renault", 10, TypeOfCar.Automatic));
        manufacturersList.add(new ManufacturerModel("Lamborghini", 11, 
        TypeOfCar.Automatic));
        manufacturersList.add(new ManufacturerModel("Suzuki", 12, TypeOfCar.Automatic));

        adapter = new CarOptionAdapter(mActivity, manufacturersList,
                R.layout.item_choose_car_manufacturer);
        mBinding.rvManufacturers.setAdapter(adapter);
        mBinding.rvManufacturers.setLayoutManager(new LinearLayoutManager(mContext));
    }

//This method is called from the viewmodel. It's working properly because it 
//is used to preselect in the recyclerview the previous saved car manufacturer 
//radio button. But the scrolling isn't working. 
  private void observeCarManufacturer(String carManufacturerBrand) {
            for (int i = 0; i < manufacturersList.size(); i++) {
                if (carManufacturerBrand.equals(manufacturersList.get(i).getName())) {
                    adapter.updateSelectedItem(i);
                    mBinding.rvNodeManufacturers.scrollToPosition(i);
                    break;
            }
        }
    }

自定义适配器:

public class CarOptionAdapter extends RecyclerView.Adapter<CarOptionAdapter.ViewHolder> {

    protected final Context mContext;
    protected final List<ManufacturerModel> mData;
    private int mSelectedItem = -1;
    private final int mLayoutResId;

    public CarOptionAdapter(final Context context, final List<ManufacturerModel> data,
                                  int mLayoutResId) {
        this.mContext = context;
        this.mData = data;
        this.mLayoutResId = mLayoutResId;
    }

    @NonNull
    @Override
    public CarOptionAdapter.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater = LayoutInflater.from(mContext);
        final View view = inflater.inflate(mLayoutResId, parent, false);
        return new ViewHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.ivManufacturer.setImageResource(R.drawable.ic_cloud);
        holder.tvManufacturer.setText(mData.get(position).getName());
        holder.radio.setChecked(position == mSelectedItem);
    }


    public int getSelectedItem() {
        return mSelectedItem;
    }

    public void updateSelectedItem(int selectedItem) {
        mSelectedItem = selectedItem;
    }

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

    public class ViewHolder extends RecyclerView.ViewHolder {

        RadioButton radio;
        TextView tvManufacturer;
        ImageView ivManufacturer;

        public ViewHolder(final View inflate) {
            super(inflate);
            radio = inflate.findViewById(R.id.radioManufacturer);
            tvManufacturer = inflate.findViewById(R.id.textManufacturer);
            ivManufacturer = inflate.findViewById(R.id.ivManufacturer);

            View.OnClickListener clickListener = v -> {
                mSelectedItem = getAdapterPosition();
                notifyItemRangeChanged(0, mData.size());
            };
            itemView.setOnClickListener(clickListener);
            radio.setOnClickListener(clickListener);
        }
    }
}

有没有其他方法可以实现滚动定位?

我意识到 recyclerView 嵌入在 nestedScrollView 中,这就是为什么滚动没有按预期工作的原因。

修复方法如下:

mBinding.rvManufacturers.post(() -> {
                        float y = mBinding.rvManufacturers.getY() + mBinding.rvManufacturers.getChildAt(selectedItem).getY();
                        nestedScrollView.smoothScrollTo(0, (int) y);
                    });

关于它的完整讨论和原始答案在这里: