因為項目的一些需求需要用到此種展現方式. 找了市面上大部分有類似功能的應用. 基本思路嵌套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.