我有一个很长的ListView,用户可以在返回前一个屏幕之前滚动它。当用户再次打开这个ListView时,我希望列表被滚动到与之前相同的位置。关于如何实现这一点,你有什么想法吗?
当前回答
Parcelable state;
@Override
public void onPause() {
// Save ListView state @ onPause
Log.d(TAG, "saving listview state");
state = listView.onSaveInstanceState();
super.onPause();
}
...
@Override
public void onViewCreated(final View view, Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
// Set new items
listView.setAdapter(adapter);
...
// Restore previous state (including selected item index and scroll position)
if(state != null) {
Log.d(TAG, "trying to restore listview state");
listView.onRestoreInstanceState(state);
}
}
其他回答
为了澄清Ryan Newsom的精彩回答并针对片段进行调整通常情况下,我们想要从主ListView片段导航到细节片段然后再返回主ListView片段
private View root;
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState)
{
if(root == null){
root = inflater.inflate(R.layout.myfragmentid,container,false);
InitializeView();
}
return root;
}
public void InitializeView()
{
ListView listView = (ListView)root.findViewById(R.id.listviewid);
BaseAdapter adapter = CreateAdapter();//Create your adapter here
listView.setAdpater(adapter);
//other initialization code
}
这里的“神奇”是,当我们从细节片段导航回ListView片段时,视图不会被重新创建,我们不设置ListView的适配器,所以一切都保持不变!
对于一些正在寻找此问题解决方案的人来说,问题的根源可能在于您设置列表视图适配器的位置。在列表视图上设置适配器后,它将重置滚动位置。只是需要考虑一下。我移动设置适配器到我的onCreateView后,我们抓取引用到列表视图,它解决了我的问题。=)
警告! !在AbsListView中有一个错误,如果ListView.getFirstVisiblePosition()为0,则不允许onSaveState()正确工作。
所以,如果你有大图像,占据了屏幕的大部分,你滚动到第二张图像,但第一张图像的一部分正在显示,滚动位置将不会被保存…
从AbsListView.java:1650(评论我)
// this will be false when the firstPosition IS 0
if (haveChildren && mFirstPosition > 0) {
...
} else {
ss.viewTop = 0;
ss.firstId = INVALID_POSITION;
ss.position = 0;
}
但在这种情况下,下面代码中的“top”将是一个负数,这将导致其他问题,阻止状态被正确恢复。所以当'top'为负时,就得到下一个子结点
// save index and top position
int index = getFirstVisiblePosition();
View v = getChildAt(0);
int top = (v == null) ? 0 : v.getTop();
if (top < 0 && getChildAt(1) != null) {
index++;
v = getChildAt(1);
top = v.getTop();
}
// parcel the index and top
// when restoring, unparcel index and top
listView.setSelectionFromTop(index, top);
我的答案是Firebase和位置0是一个变通办法
Parcelable state;
DatabaseReference everybody = db.getReference("Everybody Room List");
everybody.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
state = listView.onSaveInstanceState(); // Save
progressBar.setVisibility(View.GONE);
arrayList.clear();
for (DataSnapshot messageSnapshot : dataSnapshot.getChildren()) {
Messages messagesSpacecraft = messageSnapshot.getValue(Messages.class);
arrayList.add(messagesSpacecraft);
}
listView.setAdapter(convertView);
listView.onRestoreInstanceState(state); // Restore
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
和convertView
位置0 a添加一个您不使用的空白项
public class Chat_ConvertView_List_Room extends BaseAdapter {
private ArrayList<Messages> spacecrafts;
private Context context;
@SuppressLint("CommitPrefEdits")
Chat_ConvertView_List_Room(Context context, ArrayList<Messages> spacecrafts) {
this.context = context;
this.spacecrafts = spacecrafts;
}
@Override
public int getCount() {
return spacecrafts.size();
}
@Override
public Object getItem(int position) {
return spacecrafts.get(position);
}
@Override
public long getItemId(int position) {
return position;
}
@SuppressLint({"SetTextI18n", "SimpleDateFormat"})
@Override
public View getView(final int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = LayoutInflater.from(context).inflate(R.layout.message_model_list_room, parent, false);
}
final Messages s = (Messages) this.getItem(position);
if (position == 0) {
convertView.getLayoutParams().height = 1; // 0 does not work
} else {
convertView.getLayoutParams().height = RelativeLayout.LayoutParams.WRAP_CONTENT;
}
return convertView;
}
}
我已经看到这个工作暂时不打扰用户,我希望它为您工作
这里提供的解决方案似乎都不适合我。在我的情况下,我有一个ListView在一个片段,我替换在一个FragmentTransaction,所以一个新的片段实例创建每次片段显示,这意味着ListView状态不能存储为片段的成员。
相反,我最终将状态存储在我的自定义Application类中。下面的代码应该会让你了解它是如何工作的:
public class MyApplication extends Application {
public static HashMap<String, Parcelable> parcelableCache = new HashMap<>();
/* ... code omitted for brevity ... */
}
public class MyFragment extends Fragment{
private ListView mListView = null;
private MyAdapter mAdapter = null;
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
super.onViewCreated(view, savedInstanceState);
mAdapter = new MyAdapter(getActivity(), null, 0);
mListView = ((ListView) view.findViewById(R.id.myListView));
Parcelable listViewState = MyApplication.parcelableCache.get("my_listview_state");
if( listViewState != null )
mListView.onRestoreInstanceState(listViewState);
}
@Override
public void onPause() {
MyApplication.parcelableCache.put("my_listview_state", mListView.onSaveInstanceState());
super.onPause();
}
/* ... code omitted for brevity ... */
}
基本思想是将状态存储在片段实例之外。如果您不喜欢在应用程序类中拥有静态字段的想法,我猜您可以通过实现一个片段接口并将状态存储在您的活动中来实现它。
另一种解决方案是将其存储在SharedPreferences中,但这有点复杂,您需要确保在应用程序启动时清除它,除非您希望在应用程序启动时保持状态。
另外,为了避免“当第一项可见时滚动位置不保存”,你可以显示一个0px高度的虚拟第一项。这可以通过重写适配器中的getView()来实现,如下所示:
@Override
public View getView(int position, View convertView, ViewGroup parent) {
if( position == 0 ) {
View zeroHeightView = new View(parent.getContext());
zeroHeightView.setLayoutParams(new ViewGroup.LayoutParams(0, 0));
return zeroHeightView;
}
else
return super.getView(position, convertView, parent);
}
推荐文章
- 模块是用不兼容的Kotlin版本编译的。其元数据的二进制版本为1.5.1,预期版本为1.1.15
- 如何在Android工作室添加“libs”文件夹?
- scrollIntoView卷轴太远了
- 使用什么api来绘制其他应用程序(如Facebook的Chat Heads)?
- getDefaultSharedPreferences和getSharedPreferences的区别
- 如何模拟按钮点击使用代码?
- Android Webview给出net::ERR_CACHE_MISS消息
- Parcelable遇到IOException写入序列化对象getactivity()
- 如何在Android中动态更改菜单项文本
- 如何将Base64字符串转换为位图图像,以显示在一个ImageView?
- 新版本的Android模拟器问题-模拟器进程已终止
- 没有与请求版本匹配的NDK版本
- 如何将一个颜色整数转换为十六进制字符串在Android?
- 格式浮动到小数点后n位
- 移除一个onclick监听器