I want to make an element that is shown in the middle of ScrollView
(or ListView
) at the first and then gets stuck in the header of screen when it’s scrolled.
It’s a prototype implementation in CSS+JS: http://jsfiddle.net/minhee/aPcv4/embedded/result/.
At first glance I would make ScrollView
to include ListView
, but the official docs says:
You should never use a ScrollView with a ListView, because ListView takes care of its own vertical scrolling. Most importantly, doing this defeats all of the important optimizations in ListView for dealing with large lists, since it effectively forces the ListView to display its entire list of items to fill up the infinite container supplied by ScrollView.
So, what approaches can I try to achieve this UI?
Update: I tried StickyListHeaders, but: “it is currently not possible to have interactive elements in the header, Buttons, switches, etc. will only work when the header is not stuck.” Plus, I find it’s not very suitable for this situation. I don’t need multiple headers, but just one middle element to get stuck in the header.
You need to do 3 things: Set android:fillViewport="true" in ScrollView. The direct child of the ScroolView needs to be a LinearLayout. Your original Content will be under LinearLayout and for the Content set android:layout_gravity="center_vertical"
Only one view can be included in a ScrollView .
In Android, a ScrollView is a view group that is used to make vertically scrollable views. A scroll view contains a single direct child only. In order to place multiple views in the scroll view, one needs to make a view group(like LinearLayout) as a direct child and then we can define many views inside it.
id: In android, id attribute is used to uniquely identify a ScrollView.
I have used(or rather, tried to use) the StickyListHeaders
library in the past. After having some issues with it, I came up with the following. It is not much different from what other posters have suggested.
The main layout file activity_layout.xml
consists of a ListView
and a LinearLayout
which is invisible by default. Using the OnScrollListener's onScroll() method, the LinearLayout's
visibility is toggled. You don't need to inflate another layout or add views dynamically to your layout's parent. This is what the onScroll
method looks like:
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > 3) { // 5th row will stick
llHeader.setVisibility(View.VISIBLE);
} else {
llHeader.setVisibility(View.GONE);
}
}
Simply, toggle the visibility to get the desired effect. You can take a look at the following code. Its a working example of what you can expect. The activity contains a ListView
with a strictly barebone extension of BaseAdapter
. The ListView
is populated with numbered Buttons(one on each row, starting at 0, and going up to 19).
public class StickyHeader extends Activity {
LinearLayout llHeader;
ListView lv;
SHAdapter shAdapter;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_layout);
lv = (ListView) findViewById(R.id.listView1);
llHeader = (LinearLayout) findViewById(R.id.llHeader);
shAdapter = new SHAdapter();
lv.setAdapter(shAdapter);
lv.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem > 3) {
llHeader.setVisibility(View.VISIBLE);
} else {
llHeader.setVisibility(View.GONE);
}
}
});
}
public class SHAdapter extends BaseAdapter {
Button btCurrent;
int[] arr = new int[] {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19};
@Override
public int getCount() {
return 20;
}
@Override
public Object getItem(int arg0) {
return arr[arg0];
}
@Override
public long getItemId(int position) {
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
convertView = getLayoutInflater().inflate(R.layout.list_item_layout, null);
btCurrent = (Button) convertView.findViewById(R.id.button1);
if ((Integer)getItem(position) == 4) {
btCurrent.setText("Number " + getItem(position) + " is sticky");
} else {
btCurrent.setText("" + getItem(position));
}
return convertView;
}
}
}
activity_layout.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent" >
<ListView
android:id="@+id/listView1"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
</ListView>
<!-- This LinearLayout's visibility is toggled -->
<!-- Improvement suggested by user 'ar34z'
(see comment section below) -->
<include layout="@layout/list_item_layout" />
</RelativeLayout>
list_item_layout
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/llHeader"
android:layout_width="match_parent"
android:layout_height="50dp"
android:background="@color/white"
android:orientation="vertical" >
<Button
android:id="@+id/button1"
android:layout_gravity="center"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With