In android development, you often need to manually set the location of a ListItem. The location setting functions include:
ListView. setSelection (int position)
ListView. setSelectionFromTop (int position, int y );
Where
Position indicates the index of the specified item in ListView. Note that if a Header exists, the index starts from the Header.
Y indicates the distance to the top edge of the visible range of ListView.
Now the function has been set according to your own needs.
In this case, the ListView must be displayed from the bottom up. When the Cursor is updated, the position of the original top item (excluding the header) remains unchanged, then the new historical data is displayed above the original item.
The ListView is displayed from the bottom up, that is
[Java]
Android: stackFromBottom = "true"
However, it is found that the setting of this attribute does not affect the sorting order of the index, that is, the index of the item is increased from top to bottom, and does not change to ascending from bottom to top. Items with an index of 0 are all items (or headers) at the top of ListView ).
When the Cursor is updated, the first index will change. To hold it (R in the figure. The procedure is as follows:
(1) obtain the position of this entry in the new Cursor (posiition)
(2) obtain the position of this entry in the ListView after changing the Cursor.
(4) because of the scrolling attribute of ListView, we need to record the index of the first item visible before Cursor (ListView. getFirstVisiblePosition ())
(3) differentiate whether FirstVisiblePosition is 0 or greater than 0. Because the header, that is, the Loading in the figure, disappears after the new data is generated.
(4) When FirstVisiblePosition is 0, it actually points to the header. What we want to keep unchanged is the position of the first (R) below the header. Set FirstVisiblePosition to 1.
(5) When FirstVisiblePosition is greater than 0, it actually points to the item, but we need to set FirstVisiblePosition to 0. *
(6) we use the ListView. getChildAt (int position) function to obtain the View of the corresponding item based on FirstVisiblePosition, and then obtain the distance Y from the top of the ListView Based on The View. getTop () function.
In this way, both the position and y parameters required by ListView. setSelectionFromTop (int position, int y) are available.
* Annotation: ListView. getChildAt (int position). This position refers to the index in the visible item, which is different from the position in the cursor. Let's take a look at the ListView. getChildCount () function to get a number that is less than or equal to the number in the Cursor (if header is not considered ). Although there may be a total of 20 data records, but the interface can only see 8, then this ChildCount is about 8. On the other hand, FirstVisiblePosition takes out the index in the total number of items and then considers the missing header. Therefore, when FirstVisiblePosition is 0, it must be set to 1, and when it is greater than 0, it must be set to 0.
The code below:
Call code:
[Java]
Int headerCount = mListContainer. getListView (). getHeaderViewsCount ();
Int firstVisiblePos = mListContainer. getListView (). getFirstVisiblePosition ();
Int newCursorPosition = getPositionInNewCursor (cursor. getCount (), firstVisiblePos );
Int offsetY = getOffsetY (cursor, firstVisiblePos, newCursorPosition );
MAdapter. changeCursor (cursor );
MUpRefreshLayout. setVisibility (View. GONE );
MListContainer. getListView (). setSelectionFromTop (newCursorPosition + headerCount, offsetY );
GetPositionInNewCursor function:
[Java]
Private int getPositionInNewCursor (int newCursorCount, int firstVisiblePos ){
If (firstVisiblePos = 0 ){
FirstVisiblePos + = 1;
}
Int headerCount = mListContainer. getListView (). getHeaderViewsCount ();
Int newCursorPos = newCursorCount-mAdapter. getCount () + firstVisiblePos-headerCount;
Return newCursorPos;
}
GetOffsetY function:
[Java]
Private int getOffsetY (Cursor cursor, int firstVisiblePos, int newCursorPosition ){
Int y;
View firstVisibleItem = null;
If (firstVisiblePos = 0 ){
FirstVisibleItem = mListContainer. getListView (). getChildAt (1 );
} Else {
FirstVisibleItem = mListContainer. getListView (). getChildAt (0 );
}
Y = firstVisibleItem. getTop ();
View timeView = firstVisibleItem. findViewById (R. id. time_text_view );
If (timeView! = Null & timeView. getVisibility () = View. VISIBLE ){
Cursor curItem = (Cursor) mAdapter. getItem (newCursorPosition );
Cursor preItem = (Cursor) mAdapter. getItem (newCursorPosition-1 );
If (curItem! = Null | preItem! = Null ){
Long curTimeStamp = curItem. getLong (MessagesProjection. JEDI_CREATE_DATE_INDX );
Long preTimeStamp = preItem. getLong (MessagesProjection. JEDI_CREATE_DATE_INDX );
If (Math. abs (curTimeStamp-preTimeStamp) <= SHOW_TIME_STAMP_TEN_MINS ){
LayoutParams param = (LinearLayout. LayoutParams) mTimeView. getLayoutParams ();
Y + = mTimeView. getHeight () + param. topMargin + param. bottomMargin;
}
}
}
Return y;
}
GetOffsetY has a piece of code for calculating the height of TimeStamp in the graph. If you don't care about it, you can skip it yourself. This is because after historical data is queried, the original TimeStamp will not be displayed after refresh (merged to a time segment from the previous one ), therefore, we need to calculate its height.