27
2017
09

ListView多屏数据时footer悬停底部

1. 效果图

image

2. 需求

  1. 当数据量比较少不足一屏的时候,footer跟随数据库
  2. 当数据量多于一屏的时候,footer固定在底部

3. 分析

  1. 我们可以新建一个View作为footer,同时将这个View复制一份固定在底部,初始设置为invisible
  2. 数据量小的时候,footer默认就是跟随着ListView的,将底部View设置为invisible。数据量多的时候,将底部的View设置为visible显示出来,默认就会覆盖掉footer。
  3. 在ListView的scroll监听中对数据量的大小进行判断。如果可见项小于总项目,那么可以肯定的是数据量是多于一屏的。
  4. 如果可见项等于总项目,那么要么是不足一屏,要么最后一项footer已经部分展示在屏幕上了。可以根据footer的top值和底部View的top值进行判断。
  5. 如果footer的top值比底部View的top值小,则说明数据量不足一屏;反之则否。
  6. 加入了header或者footer后,可见项与总项目是会包含header和footer的。

4. 代码

共用xml文件,作为footer和底部View的

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#C3C3C3" android:orientation="vertical">

    <View  android:layout_width="match_parent" android:layout_height="80dp" />


</LinearLayout>

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent">

    <ListView  android:id="@+id/listView" android:layout_width="match_parent" android:layout_height="match_parent" android:cacheColorHint="@android:color/transparent" android:listSelector="@android:color/transparent" />

    <!-- 必须设置为invisible而不是gone,否则计算不出来getTop值 -->
    <FrameLayout  android:id="@+id/fl_buttom" android:layout_width="match_parent" android:layout_height="wrap_content" android:visibility="invisible" android:layout_alignParentBottom="true">

        <include layout="@layout/footer" />
    </FrameLayout>

    <Button  android:id="@+id/add" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:layout_marginLeft="10dp" android:text="添加一个Item" />

    <Button  android:id="@+id/reduce" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentRight="true" android:layout_marginTop="10dp" android:layout_marginRight="10dp" android:text="减少一个Item" />
</RelativeLayout>

MainActivity.xml

public class MainActivity extends Activity {

    private List<Item> items = new ArrayList<Item>();
    private ListView listView;
    private CommonAdapter<Item> adapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        initData();
        initListView();
        initOperation();
    }

    private void initOperation() {
        findViewById(R.id.add).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                items.add(new Item(R.mipmap.ic_launcher, "新加"));
                adapter.setDatas(items);
            }
        });

        findViewById(R.id.reduce).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if(items.size() > 0){
                    items.remove(0);
                    adapter.setDatas(items);
                }
            }
        });
    }

    private void initListView() {
        listView = (ListView) findViewById(R.id.listView);
        // CommonAdapter是我个人封装的,就是最普通的BaseAdapter
        adapter = new CommonAdapter<Item>(this, items, R.layout.item) {
            @Override
            public void convert(ViewHolder holder, Item item) {
                ImageView imageView = holder.$(R.id.img);
                TextView textView = holder.$(R.id.txt);
                imageView.setImageResource(item.getImgId());
                textView.setText(item.getText());
            }
        };
        final View footerView = View.inflate(this, R.layout.footer, null);
        listView.addFooterView(footerView);
        listView.setAdapter(adapter);

        final View buttomView = findViewById(R.id.fl_buttom);
        listView.setOnScrollListener(new AbsListView.OnScrollListener() {
            @Override
            public void onScrollStateChanged(AbsListView view, int scrollState) {

            }

            /** * 这个方法一开始就会触发。注意visibleItemCount和totalItemCount会把header和footer计算进来 */
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
                //如果可见项小于总项,如果肯定多于一屏,则直接展示底部的View
                if(visibleItemCount < totalItemCount){
                    buttomView.setVisibility(View.VISIBLE);
                }else{
                    // 可见项等于总项,不会有大于的情况。此时有两种情况。1.数量少于一屏 2.最后一项footer只显示了部分。
                    // 不管是哪种情况,底部的footer都已经显示出来了,否则visibleItemCount不会等于totalItemCount。
                    // 只要footer已经显示出来,此时调用getTop就有值,若没显示出来,getTop恒返回0。
                    if(footerView.getTop() < buttomView.getTop()){
                        //这种情况是数量不足一屏的,隐藏底部的View,让footer展示。必须是invisible,不然计算不出来getTop值
                        buttomView.setVisibility(View.INVISIBLE);
                    }else{
                        //说明footer只展示了一部分,此时也是直接展示底部的View
                        buttomView.setVisibility(View.VISIBLE);
                    }
                }
            }
        });
    }

    private void initData() {
        for(int i = 0; i < 5; i++){
            items.add(new Item(R.mipmap.ic_launcher, "测试" + i));
        }
    }

}
上一篇:Android基于google-play-services-vision:8.1.0实现动态人脸检测 下一篇:android使用opensl es进行简单的音频播放