Android-自定義多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的復用消失. 於是使用交替事件實現.

核心代碼
通過滑動的距離來 控制事件攔截 進行Scrollview和listview的交替執行
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);


    }

     配合攔截

@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進行事件判斷
 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;
        }
    }

  如何調用

 @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 所需要接收的參數:

/**
     * 頭部初始化
     *
     * @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.

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM