Android-自定义多TAB悬浮控件实现蘑菇街首页效果

出处:http://www.cnblogs.com/ImyFen/p/4967127.html

TAB悬浮控件实现蘑菇街首页效果


 

因为项目的一些需求需要用到此种展现方式.  找了市面上大部分有类似功能的应用.  基本思路嵌套ScrollView 转换事件分发给listview 实现. 但是此种方案有个缺点.

在ScrollView切换给Listview 事件的时候. 会卡顿.   体验效果并不好.    应用此方案的应用: 蘑菇街.   口袋夺宝 .    蘑菇街在快速滑动时才会卡顿.  优化处理过.


 

在找DEMO过程中. 发现此控件的方案更少. 仅有的几个问题颇多. 例如listview 长度不一时,切换VIewpager会造成大片空白. 需要重绘viewpager界面,

但是即使重绘了. 在Viewpager左右滑切换过程中. 会造成闪屏现象.    于是只能自己重写开始.

 

---------------------------下班时间到--------------回家再更新.


 

 

于是想了2种方案.

方案一: listview实现,

此方案实现相比之下较简单,不需要处理太多繁杂的地方. 但是有个致命缺点.  由于listview无法直接获取到滑动距离. 只能通过计算item高度来间接获取.  而当手势快速滑动时, 会产生惯性滑动,而惯性滑动是无法正确的

获取到滑动的高度的, 且滑动效果并不流畅. 于是此方案放弃.

方案二: scrollview 嵌套listview实现.

此Demo就采用了这种写法.  至于为什么要用Scrollview嵌套?  因为Scrollview 能准确的获得滑动的高度. 实现滑动切换非常流畅. 并且不需要重写事件分发.

就不会有了卡顿现象;

此方案并非是在整体界面中用Scrollview 嵌套所有布局.  而是在Viewpager的item里面   ScrollView嵌套listview;

 

难点:     整个控件的难点就在于 公共区域头部的处理.   悬浮窗反而是最简单的. (题外话: 主要目的就是为了写悬浮窗效果, 结果反而最简单. 蛋疼有木有!!!(╮(╯▽╰)╭ )

另外一个难点就在于Viewpager切换时的状态保存了.  此段比较绕.  我也是绕了好久才绕明白了.


 

最后:      由于是测试Demo 代码杂乱. 勿怪.  这几天将会抽取成库, 另外加上下拉刷新及加载更多功能. 希望能帮到有用的同学们把.

Demo周一附上(忘记上传网盘了.在公司电脑(。_°☆ ╲(-  –)


 

-------------------------------------------------2015.11.27分割线-----------------------------------
好吧. 终于有空更新了. 目前已封装完毕 增加了下拉刷新功能;  核心方法变动较大, 由于常规的Scrollview嵌套listview 会让listview的复用消失. 于是使用交替事件实现.<br style="margin: 0px; padding: 0px;" /><br style="margin: 0px; padding: 0px;" /> 
核心代码
通过滑动的距离来 控制事件拦截 进行Scrollview和listview的交替执行
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
protected  void  onScrollChanged( int  l,  int  t,  int  oldl,  int  oldt) {
         LogUtils.w( "滑动距离------"  + t);
         ScrollY = t;
         CheckMargin(t);
 
         if  (t >= offsetHeight -  2 ) { //上啦过程
             mSupListView.setVisibility(View.VISIBLE);
             if  (t >= offsetHeight -  2 ) {
                 Constant.RET =  false //不拦截
             else  {
                 Constant.RET =  true //拦截
             }
         else  {
             mSupListView.setVisibility(View.GONE);
             Constant.RET =  true //拦截
         }
         super .onScrollChanged(l, t, oldl, oldt);
 
 
     }

     配合拦截

1
2
3
4
5
6
7
8
9
@Override
     public  boolean  onInterceptTouchEvent(MotionEvent ev) {
         if  (mHorizontalListView.getTop() >  0  && mHorizontalListView.getTop() <= Constant.offsetHeight -  2 ) {
             Constant.RET =  super .onInterceptTouchEvent(ev);
         }
         LogUtils.w( "super.onInterceptTouchEvent(ev)="  super .onInterceptTouchEvent(ev));
 
         return  Constant.RET && mGestureDetector.onTouchEvent(ev);
     }

  

//此方法为判断是否是左右滑动 处理Viewpager事件拦截 从而不需要再自定义一个Viewpager进行事件判断
1
2
3
4
5
6
7
8
9
10
11
private  class  YScrollDetector  extends  GestureDetector.SimpleOnGestureListener {
        @Override
        public  boolean  onScroll(MotionEvent e1, MotionEvent e2,
                                float  distanceX,  float  distanceY) {
 
            if  (Math.abs(distanceY) >= Math.abs(distanceX)) {
                return  true //如果更相对于左右滑动 事件交给子控件处理.
            }
            return  false ;
        }
    }

  如何调用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
@Override
    public  View createSuccessView() {
        View view = View.inflate(getContext(), R.layout.home_fragment_context,  null );
        mScrollContainer = (LinearLayout) view.findViewById(R.id.scrollview_container);
        mLinearLayout = (LinearLayout) view.findViewById(R.id.home_banner_header); //广告头的总布局;
        mViewPager = (FragmentViewPager) view.findViewById(R.id.home_viewpager);
        mHorizontalListView = (HorizontalListView) view.findViewById(R.id.user);  //非悬浮导航
        mSupListView = (HorizontalListView) view.findViewById(R.id.Sup);  //悬浮导航
        Constant.MY_INDICATOR = mSupListView;
        imageView = (ImageView) view.findViewById(R.id.myimage);
        mHorizontalListView.setAdapter( new  OrderAdapter(getContext()));
        mSupListView.setAdapter( new  OrderAdapter(getContext()));
        RefreshHeadView = (LinearLayout) view.findViewById(R.id.scrollView_refresh_head);
        mSuspendScrollView = (SuspendScrollView) view.findViewById(R.id.home_scrollview);
        //接受参数
        mSuspendScrollView.setView(mLinearLayout, mSupListView, RefreshHeadView, mHorizontalListView,mScrollContainer);
        mSuspendScrollView.setOnRefreshScrollViewListener( new  SuspendScrollView.OnRefreshScrollViewListener() {
            @Override
            public  void  onRefresh() {
                UiUtils.showToast( "下啦刷新中" );
                //请求数据操作 子线程操作
                ThreadManager.getInstance().createLongPool().execute( new  Runnable() {
                    @Override
                    public  void  run() {
                        SystemClock.sleep( 1000 ); //模拟请求数据
                        mSuspendScrollView.completeRefresh();
 
                    }
                });
            }
 
            /**
             * 刷新完成时需要的操作  更新UI等
             */
            @Override
            public  void  onRefreshFinish() {
                UiUtils.showToast( "刷新完成" );
            }
        });
        mViewPager.setAdapter( new  HomeFragmentViewPagerAdapter(getActivity().getSupportFragmentManager()));
        mViewPager.setOffscreenPageLimit( 2 ); //设置预加载 防止切换时状态丢失
        setViewpagerHeight(mViewPager);
        initIndicator();
        return  view;
    }

  Scrollview 所需要接收的参数:

1
2
3
4
5
6
7
8
9
10
11
12
/**
      * 头部初始化
      *
      * @param banner           广告头
      * @param sup              悬浮的头布局
      * @param refreshHeadView  下啦刷新头布局
      * @param NoSup            不是悬浮的布局
      * @param mScrollContainer
      */
     public  void  setView(View banner, HorizontalListView sup, LinearLayout refreshHeadView, HorizontalListView NoSup, LinearLayout mScrollContainer) {
 
}

  

 

优化了很多细节上的处理 , 此Demo 应该是最终版了.   更贴近项目~.

最后上个最后的效果图:

 

 http://pan.baidu.com/s/1bn2tlIf 地址.

注: 转载注明出处. 谢谢各位!


 -------------------------------------------------------------2015.12.1更新------------------------------

修复转交事件卡顿BUG.

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值