美文网首页Android-ui效果自定义控件自定义View系列
悬浮导航栏StickyNavLayout的实现--适配任意数据量

悬浮导航栏StickyNavLayout的实现--适配任意数据量

作者: 皮球二二 | 来源:发表于2016-05-28 00:12 被阅读3197次

    致敬鸿洋,这篇文章是基于他的项目改造而成的

    本次主题将分成3个部分进行讲解,前2部分基本上是对鸿洋的代码解读以及一些小bug的处理,第三部分是针对鸿洋Android-StickyNavLayout不支持的功能进行优化处理。本文对应的项目地址在Github

    重头戏即将登场

    通过之前2章的学习,貌似我们的功能是完美的。这里我做出了一点点小改变

    changeItems(4);  
    private void changeItems(int num) {    
        strings.clear();    
        for (int i=0;i<num;i++) {        
            strings.add("");    
        }    
        adapter.notifyDataSetChanged();
    }
    

    我在初始化的时候只赋值4条数据进去,来看看什么情况

    bug来了

    这是什么鬼!?虽然说他是bug也好像没那么严重,只能说不是那么合理吧。我们应该达到什么效果
    1 总数据高度连列表高度都没有的时候,不能滑动
    2 总数据高度达到列表高度但是没有达到之前可以悬浮的效果时,可以滑动列表到最底端
    3 数据足够多的时候,我们继续刚才那种效果
    这三点就是我们本次主题的最终需求

    第一种情况的实现

    其实思路非常简单

    startListViewHeight=getMeasuredHeight()-id_indicatorview.getMeasuredHeight()-id_topview.getMeasuredHeight();  
    

    startListViewHeight获取listview最开始的高度
    然后我们得到总数据高度(总数据高度大家在各自项目中自行去计算,这里仅仅做一个范例,把item的高度写死成50dp了)

    public void setContentHeight(int item) {    
        this.contentHeight=item*dp2px(context, 50);
    }
    

    真正滑动的地方刚才我们也看到了,是重写的ScrollTo方法,我们只要加上一句

    if (contentHeight<startListViewHeight) {    
        y = 0;
    }
    

    即可。这样就划不动啦

    第二种情况的实现

    同样在重写的ScrollTo方法中加一句限制

    if (y>(contentHeight-startListViewHeight) && (contentHeight-startListViewHeight)>0) {   
          y=contentHeight-startListViewHeight;
    }
    
    滑动限制

    数据动态切换

    刚才貌似初次加载都不会有什么问题了,但是一旦数据切换呢,比如我直接从14条变成4条,会什么样呢?

    id_indicatorview= (LinearLayout) findViewById(R.id.id_indicatorview);
        id_indicatorview.setOnClickListener(new View.OnClickListener() {    
        @Override    
        public void onClick(View v) {        
            Toast.makeText(MainActivity.this, "click2", Toast.LENGTH_SHORT).show();        
            changeItems(4);  
        }
    });
    

    你想想看不做处理肯定是不行的,你一开始滑动到最顶部悬浮在那边,然后什么都不处理,那4条肯定孤零零的悬在那边,而且ScrollTo方法重写了,滑也滑不动了。。。

    我们首先得确定当前是何种状态

    public int getState() {    
        int state=-1;    
        if (getScrollY()==0) {        
            state=1;    //没有进行过滚动
        }    
        if (getScrollY()<mTopViewHeight) {        
            state=2;    //进行过滚动但是没有达到悬停的条件
        }   
        if (getScrollY()>=mTopViewHeight) {        
            state=3;    //已经悬停了
        }    
        return state;
    }
    

    只可能存在这三种状态。
    同样,改变数据源之后新状态也是这3种状态

    第一种情况 之前滚动了多少,原样滚回去

    第二种情况 这种情况比较复杂。如果之前是第一种状态,则回滚到现在可以滚动的最大值去;如果之前是第二种状态,则什么都不需要做;如果之前是第三种状态,那么就要判断一下现在已经滚动的距离是不是已经超过了当前最大滚动范围,没有超过,则无需处理,如果已经超过,就要把超过的部分滚回来

    第三种情况 无需改变,不管你之前是什么样的状态,我都能完美的适配你

    public void reset() {    
        isReset=true;    
        //之前滚动的状态    
        int state=getState();    
        //第一种情况
        if (this.contentHeight<startListViewHeight) {        
            scrollBy(0, -getScrollY());       
            return;    
        }    
        //第二种情况    
        if (contentHeight-startListViewHeight<mTopViewHeight) {        
            if (state==3) {          
                if (startListViewHeight+getScrollY()>contentHeight) {                
                    scrollTo(0, (contentHeight-startListViewHeight));            
                }        
            }       
            else if (state==2) {       
                if (startListViewHeight+getScrollY()>contentHeight) {                
                    scrollBy(0, -(startListViewHeight+getScrollY()-contentHeight));           
                }        
            }    
        }    
        //第三种情况
        if (contentHeight-startListViewHeight>=mTopViewHeight) {    
        }
    }
    

    这边有个isReset标志位,是用来告诉ScrollTo方法你直接滚动就行了,不要参与什么判断

    @Override
    public void scrollTo(int x, int y) {    
    if (isReset) {        
        super.scrollTo(x, y);        
        isReset=false;        
        isTopHidden=false;        
        return;    
    }
    

    至此,整个悬停功能就完美的实现了,没有什么不合理的地方,看看最终效果


    最终效果

    测试的时候直接点击中间导航条即可更改adapter数据源数量

    相关文章

      网友评论

      • eafede0b4767:控件很完美~但是能不能把log输出关闭呢?日志太多了!
      • d05229ae2f0e:你好,我想问一下,如果我的id_indicatorview是viewpager,而viewpager的item是2个fragment,每个fragment中包含一个listview,那么当我的listview的item不足一屏的时候,怎么实现让他不滑动????
        皮球二二: @gsw3430 我好像提供了一个方法,每次切换的时候要重新计算一下
        d05229ae2f0e:@r17171709
        两个fragment,一个中包含的数据是足够的,一个中包含的数据不足一屏,他们分开可以实现,但是,当俩个fragment的互相切换的时候,会互相产生影响。导致那个数据不足一屏的fragment也可以滑动,而数据足够一屏的却不可以滑动
        皮球二二: @gsw3430 我应该已经处理过了,不过建议使用官方的coordinatorLayout

      本文标题:悬浮导航栏StickyNavLayout的实现--适配任意数据量

      本文链接:https://www.haomeiwen.com/subject/kgjfdttx.html