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);
});
关于它的完整讨论和原始答案在这里:
我有一个带有 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);
});
关于它的完整讨论和原始答案在这里: