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

