因为项目的一些需求需要用到此种展现方式. 找了市面上大部分有类似功能的应用. 基本思路嵌套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的交替执行
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.