【问题标题】:Android Listview Custom Section HeaderAndroid Listview 自定义部分标题
【发布时间】:2012-02-27 21:24:35
【问题描述】:

如何在 Android 中实现 ListView 的自定义部分或标题,如 Instagram 应用程序。

http://prsarahevans.com/wp-content/uploads/2011/06/photo.PNG

当向上滚动有用户图片的栏时,名称和时间仍然存在,当其他标题栏靠近它时,然后像向上推一样动画。

谢谢。

【问题讨论】:

    标签: android listview customization


    【解决方案1】:

    我能够通过在列表视图上使用滚动监听器来解决这个问题。 (在 2.1 上测试)

    假设对于每个列表行,我都有一个如下所示的布局。有内容部分和标题部分。您对标题或内容使用什么视图类型并不重要。

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" android:background="#FFFFFF">
    
        <ImageView
            android:id="@+id/content"
            android:layout_width="fill_parent"
            android:layout_height="300dp"
            android:scaleType="centerCrop" 
            android:src="@drawable/pic"
            android:background="#aaaaff" 
            android:layout_marginTop="40dp"/>
    
        <TextView
            android:id="@+id/header"
            android:layout_width="fill_parent"
            android:layout_height="40dp"
            android:padding="12dp"
            android:text="Deneme Row"
            android:textColor="#000000" 
            android:background="#99ffffff"/>
    </RelativeLayout>
    

    活动的测试布局如下:

    <?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:orientation="vertical" >
    
        <ListView
            android:id="@+id/list"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent" >
        </ListView>
    </LinearLayout>
    

    最后,活动的代码如下。在这里,我必须有一个适配器,它使用 ViewHolder 来存储标题视图,还有一个变量来跟踪每个连续滚动事件(previousTop)的滚动变化。这是因为 offsetTopAndBottom() 改变了与之前位置相关的视图偏移量。

    public class TestActivity extends Activity implements AbsListView.OnScrollListener{
    
        ListView list; 
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.main);
            list = (ListView) findViewById(R.id.list);
            list.setAdapter(new Adapter(this));        
            list.setOnScrollListener(this); 
        }
    
        @Override
        public void onScroll(AbsListView view, int firstVisibleItem,
                int visibleItemCount, int totalItemCount) {     
            //the listview has only few children (of course according to the height of each child) who are visible
            for(int i=0; i < list.getChildCount(); i++){
                View child = list.getChildAt(i);
                ViewHolder holder = (ViewHolder) child.getTag();
    
                //if the view is the first item at the top we will do some processing
                if(i == 0){             
                    boolean isAtBottom = child.getHeight() <= holder.header.getBottom();
                    int offset = holder.previousTop - child.getTop();
                    if(!(isAtBottom && offset > 0)){                    
                        holder.previousTop = child.getTop();
                        holder.header.offsetTopAndBottom(offset);                   
                        holder.header.invalidate();
                    }
                } //if the view is not the first item it "may" need some correction because of view re-use
                else if (holder.header.getTop() != 0) {
                    int offset = -1 * holder.header.getTop(); 
                    holder.header.offsetTopAndBottom(offset);
                    holder.previousTop = 0;
                    holder.header.invalidate();
                }
            }
        }
    
        @Override
        public void onScrollStateChanged(AbsListView view, int scrollState) {}
    
        private static class Adapter extends ArrayAdapter<String> {
            public Adapter(Context context) {
                super(context, R.layout.row, R.id.header);
                for(int i=0; i < 50; i++){
                    add(Integer.toString(i));
                }
            }
    
            @Override
            public View getView(int position, View convertView, ViewGroup parent) {
                if(convertView == null){
                    convertView = LayoutInflater.from(getContext()).inflate(R.layout.row, parent, false);
                    ViewHolder holder = new ViewHolder();
                    holder.header = (TextView) convertView.findViewById(R.id.header);
                    convertView.setTag(holder);             
                }
                ViewHolder holder = (ViewHolder) convertView.getTag();
                holder.header.setText(getItem(position));
                return convertView;
            }
        }
    
        private static class ViewHolder {
            TextView header;
            int previousTop = 0;
        }
    }
    

    【讨论】:

    • 嘿 siyamed,这很有用。就我而言,我在 ListView(Parent) 内还有一个 ListView(child) 。所以当我向下滚动时,标题无法正常工作......
    • 如果 child-listview 中没有数据,那么它可以正常工作.. > sample app bitbucket.org/ashish2py/instagramheader
    • 感谢您的回答.. 但我有一个问题,我在一个列表视图中使用了 10 种 custom_row,所以,我该如何管理这个自定义标题.. 如果您对我的问题然后请回答我..谢谢。
    【解决方案2】:

    我稍微改进了 Siyamed 的问题,以便在重绘视图时标题不会消失,例如,如果列表视图项中的位图发生更改。

    我没有使用相对于最后一个位置的坐标,而是使用相对于视图顶部的坐标,并使用填充而不是偏移。

    @Override
    public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
    
        for(int i=0; i < list.getChildCount(); i++){
            View child = list.getChildAt(i);
            ViewHolder holder = (ViewHolder) child.getTag();
    
            if(i == 0){
                try {
                    boolean isAtBottom = child.getHeight() <= holder.movingHeader.getBottom();
                    if(!(isAtBottom)){
                        if (child.getTop() >= 0){}
                        else if (child.getHeight() - movingHeader.getHeight() - 1 > -child.getTop())
                        {
                            holder.movingHeader.setPadding(0, -child.getTop(), 0, 0);
                            holder.movingHeader.invalidate();
                        }
                        else {
                            holder.movingHeader.setPadding(0, child.getHeight() - movingHeader.getHeight(), 0, 0);
                            holder.movingHeader.invalidate();
                        }
                    }
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
            else if (holder.movingHeader.getPaddingTop() != 0)
            {
                holder.movingHeader.setPadding(0, 0, 0, 0);
                holder.movingHeader.invalidate();
            }
        }
    }
    

    【讨论】:

      【解决方案3】:

      如果您使用的是列表视图,那么您的列表项中有 2 个视图。一个是标题,另一个实际上是项目。

      最初隐藏标题视图,随着滚动状态的变化或用户触摸您的列表项会改变标题的可见性。

      【讨论】:

        【解决方案4】:

        在您的 setcontentview 之后执行以下代码。

            ListView list = getListView();
            View footer = getLayoutInflater().inflate(R.layout.footerlayout, list, false);
            View header = getLayoutInflater().inflate(R.layout.headerlayout, list, false);
            list.addHeaderView(header);
            list.addFooterView(footer); 
        

        【讨论】:

          【解决方案5】:

          我知道这个问题有点老了,但设法找到了 StickyListHeaders 库,它在抽象节标题的创建方面做得很好。

          https://github.com/emilsjolander/StickyListHeaders

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2013-03-14
            • 2023-03-14
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多