问题汇总:
1.界面显示不全,并且需要将TabLayout跟随ListView往上移动
2.当滑动Viewpager时ListView会突然跳到屏幕的顶部
3.当内容往上滑动,使TabLayout悬浮在顶部
问题一
问题描述:.界面显示不全,需要将TabLayout跟随ListView往上移动
解决问题的思路,首先获取ListView的整个控件的高度Height,设置外层Viewpager的高度为Height.这样Scrollview就能完全显示界面.
解决方案:
第一步:计算listview高度
使用工具类测量
public class ViewUtil {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = 0;
for (int i = 0; i < listAdapter.getCount(); i++) {
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0);
totalHeight += listItem.getMeasuredHeight();
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
listView.setLayoutParams(params);
}
/**
* 获取Listview的高度,然后设置ViewPager的高度
* @param listView
* @return
*/
public static int setListViewHeightBasedOnChildren1(ListView listView) {
//获取ListView对应的Adapter
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
// pre-condition
return 0;
}
int totalHeight = 0;
for (int i = 0, len = listAdapter.getCount(); i < len; i++) { //listAdapter.getCount()返回数据项的数目
View listItem = listAdapter.getView(i, null, listView);
listItem.measure(0, 0); //计算子项View 的宽高
totalHeight += listItem.getMeasuredHeight(); //统计所有子项的总高度
}
ViewGroup.LayoutParams params = listView.getLayoutParams();
params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1));
//listView.getDividerHeight()获取子项间分隔符占用的高度
//params.height最后得到整个ListView完整显示需要的高度
listView.setLayoutParams(params);
return params.height;
}
}
listViewHomeVPAdapter = new ListViewHomeVPAdapter(getContext(),data);
mListView.setAdapter(listViewHomeVPAdapter);
int listViewHeight = ViewUtil.setListViewHeightBasedOnChildren1(mListView);
EventBus.getDefault().post(new ListViewHeight(listViewHeight));
给Viewpager设置Height
@Subscribe(threadMode = ThreadMode.MAIN)
public void onEventMainThread(ListViewHeight listViewHeight) {
int height = listViewHeight.getListViewHeight();
ViewGroup.LayoutParams layoutParams = mViewPager.getLayoutParams();
layoutParams.height = height;
mViewPager.setLayoutParams(layoutParams);
}
现在解决了界面显示不全的问题.
第二步:自定义ScrollView
public class MyScrollView extends ScrollView {
private float xDistance, yDistance, xLast, yLast;
private OnScrollListener onScrollListener;
/**
* 主要是用在用户手指离开MyScrollView,MyScrollView还在继续滑动,我们用来保存Y的距离,然后做比较
*/
private int lastScrollY;
public MyScrollView(Context context) {
this(context, null);
}
public MyScrollView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
/**
* 设置滚动接口
* @param onScrollListener
*/
public void setOnScrollListener(OnScrollListener onScrollListener) {
this.onScrollListener = onScrollListener;
}
/**
* 用于用户手指离开MyScrollView的时候获取MyScrollView滚动的Y距离,然后回调给onScroll方法中
*/
private Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
int scrollY = MyScrollView.this.getScrollY();
//此时的距离和记录下的距离不相等,在隔5毫秒给handler发送消息
if(lastScrollY != scrollY){
lastScrollY = scrollY;
handler.sendMessageDelayed(handler.obtainMessage(), 5);
}
if(onScrollListener != null){
onScrollListener.onScroll(scrollY);
}
}
};
/**
* 重写onTouchEvent, 当用户的手在MyScrollView上面的时候,
* 直接将MyScrollView滑动的Y方向距离回调给onScroll方法中,当用户抬起手的时候,
* MyScrollView可能还在滑动,所以当用户抬起手我们隔5毫秒给handler发送消息,在handler处理
* MyScrollView滑动的距离
*/
@Override
public boolean onTouchEvent(MotionEvent ev) {
if(onScrollListener != null){
onScrollListener.onScroll(lastScrollY = this.getScrollY());
}
switch(ev.getAction()){
case MotionEvent.ACTION_UP:
handler.sendMessageDelayed(handler.obtainMessage(), 5);
break;
}
Log.d("print", "getScrollY: "+this.getScrollY());
return super.onTouchEvent(ev);
}
/**
*
* 滚动的回调接口
*
*/
public interface OnScrollListener{
/**
* 回调方法, 返回MyScrollView滑动的Y方向距离
*/
public void onScroll(int scrollY);
}
/**
*解决ViewPager与ScrollView手势冲突的问题
*/
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
xDistance = yDistance = 0f;
xLast = ev.getX();
yLast = ev.getY();
break;
case MotionEvent.ACTION_MOVE:
final float curX = ev.getX();
final float curY = ev.getY();
xDistance += Math.abs(curX - xLast);
yDistance += Math.abs(curY - yLast);
xLast = curX;
yLast = curY;
if(xDistance > yDistance){
return false;
}
}
return super.onInterceptTouchEvent(ev);
}
}
问题二:
问题描述:
在项目中用到了ScrollView嵌套ViewPager嵌套ListView情况,当滑动Viewpager时ListView会突然跳到屏幕的顶部
解决方案:
在Fragment之外的控件中添加3个属性
在ScrollView的根布局中添加属性设置
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants">
关键代码:
android:focusable="true"
android:focusableInTouchMode="true"
android:descendantFocusability="beforeDescendants"
属性是当一个为View获取焦点时,定义ViewGroup和其子控件两者之间的关系.
descendantFocousability属性的值有三种: beforeDescendants , afterDescendants , blocksDescendants.
beforeDescendants: ViewGroup会优先其子控件获取焦点.
afterDescendants: ViewGroup只有当他的子控件不需要获取焦点时才获取焦点.
blocksDescendants: ViewGroup会覆盖子类控件而直接获得焦点.
问题三:
问题描述:.当内容往上滑动,使TabLayout悬浮在顶部
需要实现的效果:
解决思路:在XML文件中放置两个RelativeLayout, 一个保持在原位置,一个在顶部占位(当需要的时候把TabLayout添加进去)
解决方案:
ViewPager所在的Activity(Fragment)中
MyScrollViewHomeFragment.setOnScrollListener(this);
@Override
public void onScroll(int scrollY) {
if (scrollY >= 600) {
if (mTabFragmentHome.getParent() != relativeLayoutTop) {
relativeLayoutCenter.removeView(mTabFragmentHome);
relativeLayoutTop.addView(mTabFragmentHome);
}
} else {
if (mTabFragmentHome.getParent() != relativeLayoutCenter) {
relativeLayoutTop.removeView(mTabFragmentHome);
relativeLayoutCenter.addView(mTabFragmentHome);
}
}
}
布局文件(此处有修改,请按照思路模仿)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.xxx.widget.MyScrollView
android:id="@+id/MyScrollView_home_fragment"
android:layout_width="match_parent"
android:layout_height="match_parent">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true">
<android.support.v4.view.ViewPager
android:id="@+id/vp_fragment_home"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/relativeLayout_center" />
<RelativeLayout
android:id="@+id/relativeLayout_center"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="@+id/GongNeng">
<android.support.design.widget.TabLayout
android:id="@+id/tab_fragment_home"
android:layout_width="match_parent"
android:layout_height="20dp"
android:background="#fff"
app:tabIndicatorColor="@color/primary"
app:tabMode="scrollable"
app:tabSelectedTextColor="@color/color_text_selected"
app:tabTextColor="@color/color_text_normal" />
</RelativeLayout>
</RelativeLayout>
</com.xxx.widget.MyScrollView>
<RelativeLayout
android:id="@+id/relativeLayout_top"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</RelativeLayout>