列表滑动固定顶部栏效果(二)

好了,接着上篇的来。这是我从别人那借鉴的。

思路是把两个固定栏简化成了一个,只是利用removeView和addView根据坐标点在页面滑动的时候动态的把固定栏在内外部切换。

先借大佬一张图(谢谢了):我们后面用到了getTop(),图片很全面的介绍了各方法取值得衡量方式


当我们拿到所需要滑动的高度时,我们需要对固定布局进行临界值做判断(这里设当前滑动值为t,所需滑动值为y)比如当我们界面一开始向上滑的时候t值是小于y值的,此时内部固定栏是不需要移除的,而当我们超过y值往回滑t值又小于y值的时候,此时内部固定栏是需要从外部移除添加到内部的,所以这里我们需要对固定栏所在的父布局(ViewGroup)做判断。

注意:两个问题,1.不要在oncreat()方法中获取距离屏幕的高度,fragmen在onResume()中获取即可,2.ScroView与ListView嵌套问题,下面有解决方案。

先看效果图:


直接上代码,自定义ScroView

public class ObservableScrollView extends ScrollView{

    public ObservableScrollView(Context context) {
        this(context,null);
    }

    public ObservableScrollView(Context context, AttributeSet attrs) {
        this(context, attrs,0);
    }

    public ObservableScrollView(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
    }


    private OnObservableScrollViewScrollChanged mOnObservableScrollViewScrollChanged;

    public void setOnObservableScrollViewScrollChanged(OnObservableScrollViewScrollChanged mOnObservableScrollViewScrollChanged) {
        this.mOnObservableScrollViewScrollChanged = mOnObservableScrollViewScrollChanged;
    }


    public interface OnObservableScrollViewScrollChanged{
        void onObservableScrollViewScrollChanged(int l, int t, int oldl, int oldt);
    }

    /**
     * @param l Current horizontal scroll origin. 当前滑动的x轴距离
     * @param t Current vertical scroll origin. 当前滑动的y轴距离
     * @param oldl Previous horizontal scroll origin. 上一次滑动的x轴距离
     * @param oldt Previous vertical scroll origin. 上一次滑动的y轴距离
     */
    @Override
    protected void onScrollChanged(int l, int t, int oldl, int oldt) {
        super.onScrollChanged(l, t, oldl, oldt);
        if(mOnObservableScrollViewScrollChanged!=null){
            mOnObservableScrollViewScrollChanged.onObservableScrollViewScrollChanged(l,t,oldl,oldt);
        }
    }
}

主界面xml布局

一定记着在ScroView的父布局加

android:focusable="true"

android:focusableInTouchMode="true"否则一进来显示的不是第一行

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

    <com.example.administrator.scrollviewhead.ObservableScrollView
        android:id="@+id/sv_contentView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        >
        <LinearLayout
            android:id="@+id/ll_contentView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical">
            <TextView
                android:id="@+id/tv_headerView"
                android:layout_width="match_parent"
                android:layout_height="200dp"
                android:text="头部布局"
                android:textSize="30sp"
                android:background="@color/colorAccent"
                android:gravity="center"/>
            <LinearLayout
                android:id="@+id/ll_topView"
                android:layout_width="match_parent"
                android:layout_height="50dp"
                android:gravity="center"
                android:orientation="vertical">
                <TextView
                    android:id="@+id/tv_topView"
                    android:layout_width="match_parent"
                    android:layout_height="50dp"
                    android:text="内层固定的布局"
                    android:background="@color/colorPrimaryDark"
                    android:textSize="30sp"
                    android:gravity="center"/>
            </LinearLayout>

            <ListView
                android:id="@+id/lv"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:layout_alignParentTop="true"
                android:fadingEdge="none"/>

        </LinearLayout>
    </com.example.administrator.scrollviewhead.ObservableScrollView>

    <LinearLayout
        android:id="@+id/ll_fixedView"
        android:layout_width="match_parent"
        android:layout_height="50dp"
        android:orientation="vertical"/>

</FrameLayout>

再看下主界面代码:

public class HomeActivity extends AppCompatActivity implements ObservableScrollView.OnObservableScrollViewScrollChanged{
    private ObservableScrollView sv_contentView;
    private LinearLayout ll_topView;
    private TextView tv_topView;
    private LinearLayout ll_fixedView;
    private ListView listView;

    MyAdapter adpater;
    //用来记录内层固定布局到屏幕顶部的距离
    private int mHeight;

    public HomeActivity() {
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_homes);
        sv_contentView= (ObservableScrollView) findViewById(R.id.sv_contentView);
        ll_topView= (LinearLayout) findViewById(R.id.ll_topView);
        tv_topView= (TextView) findViewById(R.id.tv_topView);
        ll_fixedView= (LinearLayout) findViewById(R.id.ll_fixedView);
        listView= (ListView) findViewById(R.id.lv);

        List<String> data = new ArrayList<>(100);
        for (int i = 0; i < 100; ++i) {
            data.add(String.valueOf(i));
        }

        sv_contentView.setOnObservableScrollViewScrollChanged(this);
        adpater = new MyAdapter(data,this);
        listView.setAdapter(adpater);
        // 重新计算ListView的高度
        UIUtils.fixListViewHeight(listView);

    }

    @Override
    public void onWindowFocusChanged(boolean hasFocus) {
        super.onWindowFocusChanged(hasFocus);
        if(hasFocus){
            //获取HeaderView的高度,当滑动大于等于这个高度的时候,需要把topView移除当前布局,放入到外层布局
            mHeight=ll_topView.getTop();
        }
    }

    /**
     * @param l Current horizontal scroll origin. 当前滑动的x轴距离
     * @param t Current vertical scroll origin. 当前滑动的y轴距离
     * @param oldl Previous horizontal scroll origin. 上一次滑动的x轴距离
     * @param oldt Previous vertical scroll origin. 上一次滑动的y轴距离
     */
    @Override
    public void onObservableScrollViewScrollChanged(int l, int t, int oldl, int oldt) {
        if(t>=mHeight){
            if(tv_topView.getParent()!=ll_fixedView){
                ll_topView.removeView(tv_topView);
                ll_fixedView.addView(tv_topView);
            }
        }else{
            if(tv_topView.getParent()!=ll_topView){
                ll_fixedView.removeView(tv_topView);
                ll_topView.addView(tv_topView);
            }
        }
    }
}

Adapter代码:

public class MyAdapter extends BaseAdapter {
    List<String> data;
   Context context;
    public MyAdapter(List<String> data, Context context) {
        this.data = data;
        this.context = context;

    }

    @Override
    public int getCount() {
        return data.size();
    }

    @Override
    public Object getItem(int position) {
        return data.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        View view = LayoutInflater.from(context).inflate(R.layout.item_taobao_product,null);
        TextView tvName = view.findViewById(R.id.tv_title);
        tvName.setText(data.get(position));
        return view;
    }
}

 但是这里有个问题就是ScroView嵌套ListView会只显示一行的ListView,所以要动态计算每个item的高度,动态设置ListView的高度。下面是计算的工具类

public class UIUtils {
    public static void fixListViewHeight(ListView listView) {

        // 如果没有设置数据适配器,则ListView没有子项,返回。

        ListAdapter listAdapter = listView.getAdapter();

        int totalHeight = 0;

        if (listAdapter == null) {

            return;

        }

        int len = listAdapter.getCount();
        for (int index = 0; index < len; index++) {

            View listViewItem = listAdapter.getView(index , null, listView);

            // 计算子项View 的宽高

            listViewItem.measure(0, 0);

            // 计算所有子项的高度和

            totalHeight += listViewItem.getMeasuredHeight();

        }



        ViewGroup.LayoutParams params = listView.getLayoutParams();

        // listView.getDividerHeight()获取子项间分隔符的高度

        // params.height设置ListView完全显示需要的高度

        params.height = totalHeight+ (listView.getDividerHeight() * (listAdapter.getCount() - 1));

        listView.setLayoutParams(params);

    }

}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值