我有一个很长的ListView,用户可以在返回前一个屏幕之前滚动它。当用户再次打开这个ListView时,我希望列表被滚动到与之前相同的位置。关于如何实现这一点,你有什么想法吗?


当前回答

警告! !在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);

其他回答

一个非常简单的方法:

/** Save the position **/
int currentPosition = listView.getFirstVisiblePosition();

//Here u should save the currentPosition anywhere

/** Restore the previus saved position **/
listView.setSelection(savedPosition);

方法setSelection将把列表重置为所提供的项。如果不是在触摸模式,项目将实际被选中,如果在触摸模式,项目将只定位在屏幕上。

一个更复杂的方法:

listView.setOnScrollListener(this);

//Implements the interface:
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
            int visibleItemCount, int totalItemCount) {
    mCurrentX = view.getScrollX();
    mCurrentY = view.getScrollY();
}

@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {

}

//Save anywere the x and the y

/** Restore: **/
listView.scrollTo(savedX, savedY);

使用下面的代码:

int index,top;

@Override
protected void onPause() {
    super.onPause();
    index = mList.getFirstVisiblePosition();

    View v = challengeList.getChildAt(0);
    top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());
}

无论何时你刷新你的数据使用下面的代码:

adapter.notifyDataSetChanged();
mList.setSelectionFromTop(index, top);

试试这个:

// save index and top position
int index = mList.getFirstVisiblePosition();
View v = mList.getChildAt(0);
int top = (v == null) ? 0 : (v.getTop() - mList.getPaddingTop());

// ...

// restore index and position
mList.setSelectionFromTop(index, top);

Explanation: ListView.getFirstVisiblePosition() returns the top visible list item. But this item may be partially scrolled out of view, and if you want to restore the exact scroll position of the list you need to get this offset. So ListView.getChildAt(0) returns the View for the top list item, and then View.getTop() - mList.getPaddingTop() returns its relative offset from the top of the ListView. Then, to restore the ListView's scroll position, we call ListView.setSelectionFromTop() with the index of the item we want and an offset to position its top edge from the top of the ListView.

如果你在一个活动上使用片段,你可以这样做:

public abstract class BaseFragment extends Fragment {
     private boolean mSaveView = false;
     private SoftReference<View> mViewReference;

     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          if (mSaveView) {
               if (mViewReference != null) {
                    final View savedView = mViewReference.get();
                    if (savedView != null) {
                         if (savedView.getParent() != null) {
                              ((ViewGroup) savedView.getParent()).removeView(savedView);
                              return savedView;
                         }
                    }
               }
          }

          final View view = inflater.inflate(getFragmentResource(), container, false);
          mViewReference = new SoftReference<View>(view);
          return view;
     }

     protected void setSaveView(boolean value) {
           mSaveView = value;
     }
}

public class MyFragment extends BaseFragment {
     @Override
     public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
          setSaveView(true);
          final View view = super.onCreateView(inflater, container, savedInstanceState);
          ListView placesList = (ListView) view.findViewById(R.id.places_list);
          if (placesList.getAdapter() == null) {
               placesList.setAdapter(createAdapter());
          }
     }
}

我的答案是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;
}
}

我已经看到这个工作暂时不打扰用户,我希望它为您工作