横向ListView(三) —— 添加头/尾视图及居中显示

前面的文章已经介绍横向ListView的基础实现、快速滑动和事件响应实现;可以说,通过前面两篇文章已经实现了一个完整可用的横向ListView控件,而这以后的文章将介绍的是整个控件的扩展功能,以满足日常开发过程中的特殊需求

    本文将介绍列表头/尾的添加功能实现以及整个视图在没有足够item可以铺满控件时,让显示内容剧中显示。

    为什么要实现添加头尾视图,这个我个人也不是很清楚,毕竟在开发过程中很少会有使用头尾视图的需要;不过为了学习,还为了以后也许可能有这方面的需求,所以还是选择了实现这个功能;对于内容剧中显示功能,是因为在使用这个控件时刚好有这个需求。

    有一点值得注意:头/尾视图在设计和使用的概念上不是作为列表中的item,如果这一点没有弄清楚,那么在阅读源代码时会较为困难,其中八个概念性封装的方法就尤为体现出这一点(八个方法具体见代码)

 

先上代码:

package com.hss.os.horizontallistview.history_version;

import android.content.Context;
import android.database.DataSetObserver;
import android.graphics.Rect;
import android.os.Build;
import android.support.annotation.RequiresApi;
import android.util.AttributeSet;
import android.util.Log;
import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ListAdapter;
import android.widget.Scroller;

import java.util.LinkedList;
import java.util.Queue;

/**
 * 添加头/尾视图及居中显示
 * Created by sxyx on 2017/8/8.
 */

public class HorizontalListView3 extends AdapterView<ListAdapter> {

    private Queue<View> cacheView = new LinkedList<>();//列表项缓存视图
    private ListAdapter adapter = null;
    private GestureDetector mGesture;

    private int firstItemIndex = 0;//显示的第一个子项的下标
    private int lastItemIndex = -1;//显示的最后的一个子项的下标
    private int scrollValue=0;//列表已经发生有效滚动的位移值
    private int hasToScrollValue=0;//接下来列表发生滚动所要达到的位移值
    private int maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
    private int displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)

    private Scroller mScroller;
    private int firstItemLeftEdge=0;//第一个子项的左边界
    private int lastItemRightEdge=0;//最后一个子项的右边界

    private View headView;
    private View footView;
    private boolean hasHeadView=false;
    private boolean hasFootView=false;
    private boolean canShowInMid=false;



    public HorizontalListView3(Context context) {
        super(context);
        init(context);
    }

    public HorizontalListView3(Context context, AttributeSet attrs) {
        super(context, attrs);
        init(context);
    }

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

    @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP)
    public HorizontalListView3(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
        super(context, attrs, defStyleAttr, defStyleRes);
        init(context);
    }

    private void init(Context context){
        mGesture = new GestureDetector(getContext(), mOnGesture);
        mScroller=new Scroller(context);
    }



    private void initParams(){
        mScroller.forceFinished(true);//避免在滑动过程中变换视图内容时,出现列表无法滚动的情况
        removeAllViewsInLayout();
        if(adapter!=null&&lastItemIndex<adapter.getCount())
            hasToScrollValue=scrollValue;//保持显示位置不变
        else hasToScrollValue=0;//滚动到列表头
        scrollValue=0;//列表已经发生有效滚动的位移值
        firstItemIndex = 0;//显示的第一个子项的下标
        lastItemIndex = -1;//显示的最后的一个子项的下标
        maxScrollValue=Integer.MAX_VALUE;//列表发生滚动所能达到的最大位移值(这个由最后显示的列表项决定)
        displayOffset=0;//列表显示的偏移值(用于矫正列表显示的所有子项的显示位置)
        firstItemLeftEdge=0;//第一个子项的左边界
        lastItemRightEdge=0;//最后一个子项的右边界
        if(hasHeadView||hasFootView) {
            if (hasHeadView) {
                scrollValue = headView.getMeasuredWidth();
                headView.layout(0, 0, 0, 0);
                setHeadView(headView);
            }
            if (hasFootView) {
                footView.layout(0, 0, 0, 0);
                setFootView(footView);
            }
        }else  requestLayout();
    }


    private DataSetObserver mDataObserver = new DataSetObserver() {

        @Override
        public void onChanged() {
            //执行Adapter数据改变时的逻辑
            initParams();
        }

        @Override
        public void onInvalidated() {
            //执行Adapter数据失效时的逻辑
            initParams();
        }

    };

    @Override
    public ListAdapter getAdapter() {
        return adapter;
    }

    @Override
    public void setAdapter(ListAdapter adapter) {
        if(adapter!=null){
            adapter.registerDataSetObserver(mDataObserver);
        }
        if(this.adapter!=null){
            this.adapter.unregisterDataSetObserver(mDataObserver);
        }
        this.adapter=adapter;
        requestLayout();
    }

    @Override
    public View getSelectedView() {
        return null;
    }

    @Override
    public void setSelection(int i) {

    }

    private void addAndMeasureChild(View child, int viewIndex) {
        LayoutParams params = child.getLayout
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值