使中间元素卡在标题中(ScrollView / ListView)

我想创建一个在ScrollView (或ListView )中间显示的元素,然后在滚动时卡在屏幕的标题中。

它是CSS + JS中的原型实现: http : //jsfiddle.net/minhee/aPcv4/embedded/result/ 。

乍一看,我会让ScrollView包含ListView ,但官方文档说:

您永远不应该使用带有ListView的ScrollView,因为ListView负责自己的垂直滚动。 最重要的是,这样做会破坏ListView中处理大型列表的所有重要优化,因为它有效地强制ListView显示其整个项目列表以填充ScrollView提供的无限容器。

那么,我可以尝试用什么方法来实现这个UI?

更新 :我尝试过StickyListHeaders ,但是:“它目前不可能在标题中有交互元素,按钮,开关等只有在标题没有卡住时才会起作用。”另外,我发现它不适合这种情况。 我不需要多个标题,但只需要一个中间元素卡在标题中。

我过去曾使用(或者更确切地说,试图使用) StickyListHeaders库。 在遇到一些问题之后,我想出了以下内容。 它与其他海报的建议没什么不同。

主布局文件activity_layout.xmlListViewLinearLayout组成,默认情况下不可见。 使用OnScrollListener的onScroll()方法,可以切换LinearLayout's可见性。 您无需为另一个布局充气或动态添加视图到布局的父级。 这就是onScroll方法的样子:

 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); } } 

简单地说,切换可见性以获得所需的效果。 您可以查看以下代码。 它是您可以期待的工作示例。 该活动包含一个ListView ,其严格的基本扩展名为BaseAdapterListView使用编号的按钮填充(每行一个,从0开始,最多到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

        

list_item_layout

    

这是用于说明主要思想的最简单的代码:

 listView.setOnScrollListener(new OnScrollListener() { ViewGroup mainView = (ViewGroup) findViewById(R.id.main); View pinnedView = null; @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (firstVisibleItem < PINNED_ITEM) { mainView.removeView(pinnedView); pinnedView = null; } else if (pinnedView == null) { pinnedView = adapter.getView(PINNED_ITEM, null, view); pinnedView.setBackgroundColor(0xFF000000); mainView.addView(pinnedView); } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) {} }); 

我有一个FrameLayoutFrameLayout包含我的ListView

    

PINNED_ITEM是项目的位置(例如, PINNED_ITEM = 2 )。 此布局充当列表的叠加层。 ScrollListener跟踪当前可见的项目,如果它检测到项目应该固定,则会将其添加到布局中,否则将其删除。

pinnedView.setBackgroundColor(0xFF000000); 需要为项目设置不透明背景。 如果您不这样做,该项目将是透明的。 您可以根据需要调整背景(例如,您可以使用当前主题属性的背景)。

为了实现这一点,我将listView放在relativeLayout中并在滚动条上添加一个监听器。 然后在其中,当firstVisibleItem改变时,我将复制你需要的itemView并将其显示在listView上。

以下是我的想法的简短示例。 唯一的事情是重复的视图必须是不透明的。

 import android.app.Activity; import android.os.Bundle; import android.view.View; import android.view.ViewGroup.LayoutParams; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.ArrayAdapter; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.RelativeLayout; public class MainActivity extends Activity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); /*Create listView inside a relativelayout*/ final RelativeLayout rl = new RelativeLayout(this); final ListView lv = new ListView(this); rl.addView(lv); /* Set it as a content view*/ setContentView(rl); /*populate it*/ String[] items = { "Cupcake", "Donut", "Eclair", "Froyo", "Gingerbread", "Honeycomb", "Ice Cream Sandwich", "Jelly Bean"}; int size = 10; String[] arrayItems = new String[items.length*size]; for(int i = 0; i < arrayItems.length; i++) arrayItems[i] = items[i%items.length] + " " + i; /* Need to use a non transparent view*/ final ArrayAdapter adapter = new ArrayAdapter(this, R.layout.simple_list_item_1_opaque, arrayItems); lv.setAdapter(adapter); /* Choose the item to stick*/ final int itemToStick = 3; /* Create things needed for duplication */ final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.ALIGN_PARENT_TOP, 1); final RelativeLayout.LayoutParams selectorParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, lv.getDividerHeight()); lv.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // TODO Auto-generated method stub } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if(itemToStick < = firstVisibleItem && rl.getChildCount() == 1) { /* Put view in a linearlayout in order to be able to add the sepline */ LinearLayout ll = new LinearLayout(view.getContext()); ll.setOrientation(LinearLayout.VERTICAL); ll.addView(adapter.getView(itemToStick, null, null),params); /* Create Divider */ View selector = new LinearLayout(view.getContext()); selector.setBackground(lv.getDivider()); /* add views*/ ll.addView(selector,selectorParams); rl.addView(ll,params); } /* Remove view when scrolling up to it */ else if(itemToStick > firstVisibleItem) { if(rl.getChildCount() > 1) rl.removeViewAt(1); } } }); } } 

而simple_list_item_1_opaque:

 < ?xml version="1.0" encoding="utf-8"?>