先来看看要实现布局的样式哈,我感觉手动画的更详细嘿嘿。
要实现的就是这样的复杂布局,这里面涉及到各种嵌套滑动的冲突,还涉及ListView的上拉加载,接下来一点点开始哈。
首先从整体看就会看到ScrollView和ListView,我们写过他俩嵌套的都知道,他俩有冲突,所以这里我们就要对ListView下手啦。
如果单纯的想解决ScrollView嵌套ListView冲突,使用如下方法会出现一个问题,就是ListView会默认的滑到顶部(这个之后说哈)
他俩冲突归根结底是高度问题,所以解决ListView的高度也就解决他俩的嵌套滑动问题了。
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_MOVE){
return true;
}
return super.dispatchTouchEvent(ev);
}
}
这里要注意的是高度给了它最大值,这样就导致了ListView的滑动监听失效了,那么怎么才能监听ListView到底了呢?----重写ScrollView
public class ScrollBottomView extends ScrollView {
private int downX;
private int downY;
private int mTouchSlop;
private int type;
public int getType() {
return type;
}
public void setType(int type) {
this.type = type;
}
private ScrollViewToBottomListener scrollViewListener = null;
private OnScrollViewToBottomLiatener onScrollViewToBottomLiatener = null;
public ScrollBottomView(Context context) {
super(context);
}
public ScrollBottomView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public ScrollBottomView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public void setScrollViewListener(ScrollViewToBottomListener scrollViewListener) {
this.scrollViewListener = scrollViewListener;
}
public void setOnScrollViewToBottomLiatener(OnScrollViewToBottomLiatener onScrollViewToBottomLiatener){
this.onScrollViewToBottomLiatener = onScrollViewToBottomLiatener;
}
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
View view = (View) getChildAt(getChildCount() - 1);
int d = view.getBottom();
d -= (getHeight() + getScrollY());
// Log.e("---------->","d"+d);
if (d == 0) {
if (onScrollViewToBottomLiatener != null) {
onScrollViewToBottomLiatener.onScrollViewToBottomListener(type);
}
} else {
if (scrollViewListener != null) {
scrollViewListener.onScrollChanged(this, l, t, oldl, oldt);
}
}
}
interface OnScrollViewToBottomLiatener {
void onScrollViewToBottomListener();
}
}
监听ScrollView是否到底了,间接的监听了ListView到底了
当我们用ScrollView嵌套ViewPager的时候,如果每个ViewPager的页面高度不同会导致下面有一部分的空白,所以要在ViewPager改变页面的时候重置它的高度,所以要重写ViewPager了
public class ChildViewPager extends ViewPager {
private int current;
/**
* 保存position与对于的View
*/
private HashMap maps = new LinkedHashMap();
public ChildViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ChildViewPager(Context context) {
super(context);
}
public int getCurrent() {
return current;
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
// 下面遍历所有child的高度
for (int i = 0; i < this.getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
// 采用最大的view的高度
maps.put(i, h);
}
if (getChildCount() > 0) {
height = getChildAt(current).getMeasuredHeight();
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public void resetHeight(int current) {
this.current = current;
if (maps.size() > current) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
if (layoutParams == null) {
layoutParams = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, maps.get(current));
} else {
layoutParams.height = maps.get(current);
}
setLayoutParams(layoutParams);
}
}
}
看到resetHeight这个方法没有,给ViewPager设置监听,在onPageSelected方法中调用这个方法,来改变ViewPager的高度
注意:
1、得到ViewPager后要给它设置一个属性,来避免ListView滑到顶部
viewPager.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
2、如果编译时ViewPager出错要设置如下代码
//有几页设置几页
viewPager.setOffscreenPageLimit(3);
public class MyListViewFragment extends Fragment {
private MyListView myListView;
private ArrayAdapter adapter;
private List list;
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.fragment_mylistview,container,false);
myListView = (MyListView) view.findViewById(R.id.listView);
list = new ArrayList<>();
for(int i =0;i<30;i++){
list.add("数据:"+i);
}
adapter = new ArrayAdapter(getActivity(),android.R.layout.simple_list_item_1,list);
myListView.setAdapter(adapter);
return view;
}
public void loadData(){
//加载数据list.add()……别忘了刷新哈
}
}
我认为主要的都写在标注里了,一个是上拉加载,一个是ViewPager的相关设置
public class ScrollViewEnterActivity extends AppCompatActivity {
private ScrollBottomView mScrollView;
private ChildViewPager viewPager;
private TabLayout tabLayout;
private MyFragmentAdapter adapter;
private List fragments;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_scroll_view_enter);
viewPager = (ChildViewPager) findViewById(R.id.viewpager);
tabLayout = (TabLayout) findViewById(R.id.tablayout);
mScrollView = (ScrollBottomView) findViewById(R.id.activity_scroll_view_enter);
mScrollView.setOnScrollViewToBottomLiatener(new ScrollBottomView.OnScrollViewToBottomLiatener() {
@Override
public void onScrollViewToBottomListener(int type) {
//滑到底部刷新每个tab中的数据
fragments.get(viewPager.getCurrent()).loadData();
}
});
fragments = new ArrayList<>();
for(int i = 0;i<3;i++){
fragments.add(new MyListViewFragment());
}
adapter = new MyFragmentAdapter(getSupportFragmentManager());
viewPager.setAdapter(adapter);
tabLayout.setupWithViewPager(viewPager);
//设置欲缓存页
viewPager.setOffscreenPageLimit(3);
//我通过xml设置该属性不管用,这样好用(不知道为什么),设置该属性目的是防止listView(ViewPager)跳到顶部
viewPager.setDescendantFocusability(ViewGroup.FOCUS_BLOCK_DESCENDANTS);
viewPager.setOnPageChangeListener(new ViewPager.OnPageChangeListener() {
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
viewPager.resetHeight(position);
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
}
private class MyFragmentAdapter extends FragmentPagerAdapter{
public MyFragmentAdapter(FragmentManager fm) {
super(fm);
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return 3;
}
@Override
public CharSequence getPageTitle(int position) {
return "标题"+position;
}
}
}
看看XML文件吧
"1.0" encoding="utf-8"?>
<com.example.ws.scrollviewdemo.ScrollBottomView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_scroll_view_enter"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.example.ws.scrollviewdemo.ScrollViewEnterActivity">
"match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
"match_parent"
android:layout_height="300dp"
android:background="@color/color_00ff66"/>
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="各种View" />
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="随意的View" />
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="@color/color_ff6b00" />
"match_parent"
android:layout_height="wrap_content"
android:src="@mipmap/ic_launcher"/>
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="动不动" />
.support.design.widget.TabLayout
android:id="@+id/tablayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
.support.design.widget.TabLayout>
<com.example.ws.scrollviewdemo.ChildViewPager
android:id="@+id/viewpager"
android:layout_width="match_parent"
android:layout_height="wrap_content"
>
com.example.ws.scrollviewdemo.ChildViewPager>
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="1" />
"match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="2" />
com.example.ws.scrollviewdemo.ScrollBottomView>