Android: 如何在项目被编辑并重新保存后滚动回 RecyclerView 项目?
Android: how to scroll back to RecyclerView item, after item is edited and re-saved?
我有一个带有 CardView 的 RecyclerView 列表,它工作正常。当用户在名为 ActActivity 的输入 UI 上输入数据时,将创建 CardView。当用户稍后单击 CardView 以编辑原始数据时,onItemClick 方法会使用捕获适配器中正确的 CardView 项目位置的 start 方法再次启动 ActActivity。
当用户点击 UI 上的保存按钮保存编辑的数据时,ActActivity UI 关闭并自动重新加载 RecyclerView 列表(MainActivity)和更新的 CardView显示在 RecyclerView 列表中。我的问题是 RecyclerView 在重新加载时总是滚动到 CardView 项目列表的顶部。我希望列表 return 到单击要编辑的原始 CardView。我不知何故需要在 Adapter 中获取原始项目位置,并在重新创建时将其传回 RecyclerView。我需要让 RecyclerView 知道该位置是针对刚刚编辑的 CardView 而不是新的 CardView。关于如何完成的任何想法?
MainActivity.java:
public class MainActivity extends AppCompatActivity
...
void loadData(){
SQLiteDB sqLiteDB = SQLiteDB.getInstance(this);
List<Contact> contactList = new ArrayList<>();
Cursor cursor = sqLiteDB.retrieve();
Contact contact;
cursor...
Adapter.addAll(contactList);
@Override
public void onItemClick(int position, final View view) {
cardview = (CardView) view;
ActActivity.start(this, Adapter.getItem(position));
}
ActActivity.java:
public class ActActivity extends AppCompatActivity {
...
private Contact contact;
public static void start(Context context){
Intent intent = new Intent(context, ActActivity.class);
context.startActivity(intent);
}
public static void start(Context context, Contact contact){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
context.startActivity(intent);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout.activ_act);
// Fetch data from a parcelable object passed from the MainActivity.
contact = getIntent().getParcelableExtra(ActActivity.class.getSimpleName());
...
// Update edited EditText lines to the data Model via contact
contact.setDataInput(xEditText.getText().toString());
// Update the data in the SQLite database.
sqLiteDB.update(contact);
ActActivity.this.finish();
Adapter.java:
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Contact> contactList;
public Adapter(Context context) {
this.context = context;
this.contactList = new ArrayList<>();
}
Logcat 输出:
RuntimeException:无法恢复 activity {com.example.jdw.v53/com.wimso.v053.MainActivity}:java.lang.NullPointerException
在 android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575)
在 android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
在 android.os.Handler.dispatchMessage(Handler.java:99)
在 android.os.Looper.loop(Looper.java:137)
在 android.app.ActivityThread.main(ActivityThread.java:4745)
在 java.lang.reflect.Method.invokeNative(本机方法)
在 java.lang.reflect.Method.invoke(Method.java:511)
在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
在 dalvik.system.NativeStart.main(本机方法)
原因:java.lang.NullPointerException
在 com.wimso.v053.MainActivity.onResume(MainActivity.java:370)
在 android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184)
在 android.app.Activity.performResume(Activity.java:5082)
在 android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565)
在 android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603)
在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237)
在 android.os.Handler.dispatchMessage(Handler.java:99)
在 android.os.Looper.loop(Looper.java:137)
在 android.app.ActivityThread.main(ActivityThread.java:4745)
在 java.lang.reflect.Method.invokeNative(本机方法)
在 java.lang.reflect.Method.invoke(Method.java:511)
在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786)
在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
在 dalvik.system.NativeStart.main(本机方法)
执行以下步骤 -
1. 跟踪用户点击编辑的卡的适配器位置(clickPosition)。您可以通过 MainActivity 中的状态变量保留此内容。
- 当 MainActivity 恢复时,检查它是否在卡片编辑后启动,如果是,调用 api -
recyclerView.scrollToPosition(*clickPosition*)
当然,这将适用于以下条件 -
1.在ActActivity中没有并发修改recycler视图数据集。
2. 如果是新卡或删除卡操作,可能必须以稍微不同的方式进行处理
为此,第一步是当用户单击卡片时,将其位置保存在您首选的存储选项中,然后在重新加载时 RecyclerView
您可以平滑滚动到特定位置。为此,您需要创建自定义 LinearLayoutManager
。这就是你的做法:
public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {
public LinearLayoutManagerWithSmoothScroller(Context context) {
super(context, VERTICAL, false);
}
public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManagerWithSmoothScroller.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
然后将其分配给您的 RecyclerView
并调用 smoothScrollToPosition()
。
recyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(context));
recyclerView.smoothScrollToPosition(position);
您可以使用 context.startActivityForResult(intent,REQUEST_CODE);
启动 ActActivity
class,如下所示
public static void start(Context context, Contact contact,int position){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
intent.putExtra("position", position);
context.startActivityForResult(intent,2);
}
一旦 ActActivity 完成保存数据,您可以使用 setResult(intent)
将结果中的适配器位置设置回 main Activity
一旦你在MainonActivityResult()
中得到ResultActivity,你就会知道你已经编辑回来了,所以你可以使用这个方法滚动到位置,如下图
// Call Back method to get the Message form other Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed here it is 2
if(requestCode==2)
{
int position=data.getIntExtra("position", 0);
//do all your adapter resetting here for recyclerView
linearLayoutManager.scrollToPositionWithOffset(position, 0);
}
}
我有一个带有 CardView 的 RecyclerView 列表,它工作正常。当用户在名为 ActActivity 的输入 UI 上输入数据时,将创建 CardView。当用户稍后单击 CardView 以编辑原始数据时,onItemClick 方法会使用捕获适配器中正确的 CardView 项目位置的 start 方法再次启动 ActActivity。
当用户点击 UI 上的保存按钮保存编辑的数据时,ActActivity UI 关闭并自动重新加载 RecyclerView 列表(MainActivity)和更新的 CardView显示在 RecyclerView 列表中。我的问题是 RecyclerView 在重新加载时总是滚动到 CardView 项目列表的顶部。我希望列表 return 到单击要编辑的原始 CardView。我不知何故需要在 Adapter 中获取原始项目位置,并在重新创建时将其传回 RecyclerView。我需要让 RecyclerView 知道该位置是针对刚刚编辑的 CardView 而不是新的 CardView。关于如何完成的任何想法?
MainActivity.java:
public class MainActivity extends AppCompatActivity
...
void loadData(){
SQLiteDB sqLiteDB = SQLiteDB.getInstance(this);
List<Contact> contactList = new ArrayList<>();
Cursor cursor = sqLiteDB.retrieve();
Contact contact;
cursor...
Adapter.addAll(contactList);
@Override
public void onItemClick(int position, final View view) {
cardview = (CardView) view;
ActActivity.start(this, Adapter.getItem(position));
}
ActActivity.java:
public class ActActivity extends AppCompatActivity {
...
private Contact contact;
public static void start(Context context){
Intent intent = new Intent(context, ActActivity.class);
context.startActivity(intent);
}
public static void start(Context context, Contact contact){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
context.startActivity(intent);
}
@Override
protected void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(layout.activ_act);
// Fetch data from a parcelable object passed from the MainActivity.
contact = getIntent().getParcelableExtra(ActActivity.class.getSimpleName());
...
// Update edited EditText lines to the data Model via contact
contact.setDataInput(xEditText.getText().toString());
// Update the data in the SQLite database.
sqLiteDB.update(contact);
ActActivity.this.finish();
Adapter.java:
public class Adapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
private List<Contact> contactList;
public Adapter(Context context) {
this.context = context;
this.contactList = new ArrayList<>();
}
Logcat 输出:
RuntimeException:无法恢复 activity {com.example.jdw.v53/com.wimso.v053.MainActivity}:java.lang.NullPointerException 在 android.app.ActivityThread.performResumeActivity(ActivityThread.java:2575) 在 android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) 在 android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:137) 在 android.app.ActivityThread.main(ActivityThread.java:4745) 在 java.lang.reflect.Method.invokeNative(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:511) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 在 dalvik.system.NativeStart.main(本机方法) 原因:java.lang.NullPointerException 在 com.wimso.v053.MainActivity.onResume(MainActivity.java:370) 在 android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1184) 在 android.app.Activity.performResume(Activity.java:5082) 在 android.app.ActivityThread.performResumeActivity(ActivityThread.java:2565) 在 android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2603) 在 android.app.ActivityThread$H.handleMessage(ActivityThread.java:1237) 在 android.os.Handler.dispatchMessage(Handler.java:99) 在 android.os.Looper.loop(Looper.java:137) 在 android.app.ActivityThread.main(ActivityThread.java:4745) 在 java.lang.reflect.Method.invokeNative(本机方法) 在 java.lang.reflect.Method.invoke(Method.java:511) 在 com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 在 com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 在 dalvik.system.NativeStart.main(本机方法)
执行以下步骤 - 1. 跟踪用户点击编辑的卡的适配器位置(clickPosition)。您可以通过 MainActivity 中的状态变量保留此内容。
- 当 MainActivity 恢复时,检查它是否在卡片编辑后启动,如果是,调用 api -
recyclerView.scrollToPosition(*clickPosition*)
当然,这将适用于以下条件 - 1.在ActActivity中没有并发修改recycler视图数据集。 2. 如果是新卡或删除卡操作,可能必须以稍微不同的方式进行处理
为此,第一步是当用户单击卡片时,将其位置保存在您首选的存储选项中,然后在重新加载时 RecyclerView
您可以平滑滚动到特定位置。为此,您需要创建自定义 LinearLayoutManager
。这就是你的做法:
public class LinearLayoutManagerWithSmoothScroller extends LinearLayoutManager {
public LinearLayoutManagerWithSmoothScroller(Context context) {
super(context, VERTICAL, false);
}
public LinearLayoutManagerWithSmoothScroller(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
@Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state,
int position) {
RecyclerView.SmoothScroller smoothScroller = new TopSnappedSmoothScroller(recyclerView.getContext());
smoothScroller.setTargetPosition(position);
startSmoothScroll(smoothScroller);
}
private class TopSnappedSmoothScroller extends LinearSmoothScroller {
public TopSnappedSmoothScroller(Context context) {
super(context);
}
@Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return LinearLayoutManagerWithSmoothScroller.this
.computeScrollVectorForPosition(targetPosition);
}
@Override
protected int getVerticalSnapPreference() {
return SNAP_TO_START;
}
}
}
然后将其分配给您的 RecyclerView
并调用 smoothScrollToPosition()
。
recyclerView.setLayoutManager(new LinearLayoutManagerWithSmoothScroller(context));
recyclerView.smoothScrollToPosition(position);
您可以使用 context.startActivityForResult(intent,REQUEST_CODE);
启动 ActActivity
class,如下所示
public static void start(Context context, Contact contact,int position){
Intent intent = new Intent(context, ActActivity.class);
// From the OnItemClick method in the MainActivity the RecyclerView item
// position from the Adapter is passed into a putExtra bundle that the
// intent carries to this Activity. The data is then copied in the onCreate()
// below using getIntent().getParcelableExtra(). So this is to update an
// existing CardView item.
intent.putExtra(ActActivity.class.getSimpleName(), contact);
intent.putExtra("position", position);
context.startActivityForResult(intent,2);
}
一旦 ActActivity 完成保存数据,您可以使用 setResult(intent)
一旦你在MainonActivityResult()
中得到ResultActivity,你就会知道你已经编辑回来了,所以你可以使用这个方法滚动到位置,如下图
// Call Back method to get the Message form other Activity
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data)
{
super.onActivityResult(requestCode, resultCode, data);
// check if the request code is same as what is passed here it is 2
if(requestCode==2)
{
int position=data.getIntExtra("position", 0);
//do all your adapter resetting here for recyclerView
linearLayoutManager.scrollToPositionWithOffset(position, 0);
}
}