您的位置:首页 > 其它

解决ScrollView嵌套ListView,GridView,ViewPager

2016-04-14 16:17 295 查看
前言:

1.Google是不推荐在ScrollView 中放入一个可滚动的菜单的,比如放置一个ListView、GridView、ViewPager这些控件的,尽量不要让两者嵌套,但有时候还是有这个需求,先不管它合不合理。

2.如果直接在ScrollView中嵌套只会出现一行,(重点是只显示一行)然后在其中滚动,这样不是很好,下面是我的整理,希望对大家有帮助,我也是从网上摘抄的。

一、在ScrollView中嵌套ListView,有两种方法

第一种是自定义View,继承ListView代码如下:

[java] view
plain copy







import android.content.Context;

import android.util.AttributeSet;

import android.widget.ListView;

public class MyListView extends ListView {

public MyListView(Context context) {

super(context);

}

public MyListView(Context context, AttributeSet attrs, int defStyle) {

super(context, attrs, defStyle);

}

public MyListView(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,

MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, expandSpec);

}

}

第二种

[java] view
plain copy







import android.view.View;

import android.view.ViewGroup;

import android.widget.ListAdapter;

import android.widget.ListView;

public class Utility {

public static void setListViewHeightBasedOnChildren(ListView listView) {

ListAdapter listAdapter = listView.getAdapter();

if (listAdapter == null) {

// pre-condition

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);

}

}

第二种在setAdapter之后调用Utility.setListViewHeightBasedOnChildren(listview)这个方法,有些资料说只能item的根布局要LinearLayout,但是我的跟布局为RelativeLayout也可以的。
这两种都可以,但是在有些情况下中能用第一种,比如你显示ListView是一个ListFragment就只能用第二种方法了。

二、在ScrollView中嵌套GridView

[java] view
plain copy







import android.content.Context;

import android.util.AttributeSet;

import android.widget.GridView;

public class NoScrollGridView extends GridView {

public NoScrollGridView(Context context) {

super(context);

}

public NoScrollGridView(Context context, AttributeSet attrs) {

super(context, attrs);

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, expandSpec);

}

}

三、在ScrollView中嵌套ViewPager,也有两种方法

第一种自定义ScrollView

[java] view
plain copy







import android.content.Context;

import android.util.AttributeSet;

import android.view.MotionEvent;

import android.widget.ScrollView;

/**

* 能够兼容ViewPager的ScrollView

*

* @Description: 解决了ViewPager在ScrollView中的滑动反弹问题

*/

public class ScrollViewExtend extends ScrollView {

// 滑动距离及坐标

private float xDistance, yDistance, xLast, yLast;

public ScrollViewExtend(Context context, AttributeSet attrs) {

super(context, attrs);

}

@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);

}

}

第二种是自定义ViewPager

[java] view
plain copy







import android.content.Context;

import android.graphics.PointF;

import android.support.v4.view.ViewPager;

import android.util.AttributeSet;

import android.view.MotionEvent;

/**

* 嵌套在ScrollView中的ViewPager,解决冲突

* @author m3

*

*/

public class ChildViewPager extends ViewPager {

/** 触摸时按下的点 **/

PointF downP = new PointF();

/** 触摸时当前的点 **/

PointF curP = new PointF();

OnSingleTouchListener onSingleTouchListener;

public ChildViewPager(Context context, AttributeSet attrs) {

super(context, attrs);

// TODO Auto-generated constructor stub

}

public ChildViewPager(Context context) {

super(context);

// TODO Auto-generated constructor stub

}

@Override

public boolean onInterceptTouchEvent(MotionEvent arg0) {

// TODO Auto-generated method stub

// 当拦截触摸事件到达此位置的时候,返回true,

// 说明将onTouch拦截在此控件,进而执行此控件的onTouchEvent

return true;

}

@Override

public boolean onTouchEvent(MotionEvent arg0) {

// TODO Auto-generated method stub

// 每次进行onTouch事件都记录当前的按下的坐标

curP.x = arg0.getX();

curP.y = arg0.getY();

if (arg0.getAction() == MotionEvent.ACTION_DOWN) {

// 记录按下时候的坐标

// 切记不可用 downP = curP ,这样在改变curP的时候,downP也会改变

downP.x = arg0.getX();

downP.y = arg0.getY();

// 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰

getParent().requestDisallowInterceptTouchEvent(true);

}

if (arg0.getAction() == MotionEvent.ACTION_MOVE) {

// 此句代码是为了通知他的父ViewPager现在进行的是本控件的操作,不要对我的操作进行干扰

getParent().requestDisallowInterceptTouchEvent(true);

}

if (arg0.getAction() == MotionEvent.ACTION_UP) {

// 在up时判断是否按下和松手的坐标为一个点

// 如果是一个点,将执行点击事件,这是我自己写的点击事件,而不是onclick

if (downP.x == curP.x && downP.y == curP.y) {

onSingleTouch();

return true;

}

}

return super.onTouchEvent(arg0);

}

/**

* 单击

*/

public void onSingleTouch() {

if (onSingleTouchListener != null) {

onSingleTouchListener.onSingleTouch();

}

}

/**

* 创建点击事件接口

*

* @author wanpg

*

*/

public interface OnSingleTouchListener {

public void onSingleTouch();

}

public void setOnSingleTouchListener(

OnSingleTouchListener onSingleTouchListener) {

this.onSingleTouchListener = onSingleTouchListener;

}

}

第二个问题在ScrollView嵌套ListView,GridView,如果这些子控件很长超出了屏幕的高度,那么ScrollView会自动滚到底部,但是我们需要默认在顶部,我们要在ListView和GridView上面的view中加入,一下代码即可解决:

[java] view
plain copy







view.setFocusable(true);

view.setFocusableInTouchMode(true);

view.requestFocus();

这段代码在初始化的时候就让该界面的顶部的某一个控件获得焦点,滚动条自然就显示到顶部了。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: