ScrollView巢狀ListView,GridView,ViewPager,以及這些控制元件自動滾動到底部問題的解決
阿新 • • 發佈:2019-01-30
Google是不推薦在ScrollView 中放入一個可滾動的選單的,比如放置一個ListView、GridView、ViewPager這些控制元件的,儘量不要讓兩者巢狀,但有時候還是有這個需求,先不管它合不合理。如果直接在ScrollView中巢狀只會出現一行,然後在其中滾動,這樣不是很好,下面是我的整理,希望對大家有幫助,我也是從網上摘抄的,當然加入了一些我自己的東西。
一、在ScrollView中巢狀ListView,有兩張方法
第一種是自定義View,繼承ListView程式碼如下:
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.ListView;
- publicclass 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
- protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
- MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
- }
- import android.view.View;
- import android.view.ViewGroup;
- import android.widget.ListAdapter;
- import android.widget.ListView;
- publicclass Utility {
- publicstaticvoid 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
- import android.content.Context;
- import android.util.AttributeSet;
- import android.widget.GridView;
- publicclass NoScrollGridView extends GridView {
- public NoScrollGridView(Context context) {
- super(context);
- }
- public NoScrollGridView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- protectedvoid onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
- super.onMeasure(widthMeasureSpec, expandSpec);
- }
- }
第一種自定義ScrollView
- import android.content.Context;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.widget.ScrollView;
- /**
- * 能夠相容ViewPager的ScrollView
- *
- * @Description: 解決了ViewPager在ScrollView中的滑動反彈問題
- */
- publicclass ScrollViewExtend extends ScrollView {
- // 滑動距離及座標
- privatefloat xDistance, yDistance, xLast, yLast;
- public ScrollViewExtend(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- @Override
- publicboolean onInterceptTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- xDistance = yDistance = 0f;
- xLast = ev.getX();
- yLast = ev.getY();
- break;
- case MotionEvent.ACTION_MOVE:
- finalfloat curX = ev.getX();
- finalfloat curY = ev.getY();
- xDistance += Math.abs(curX - xLast);
- yDistance += Math.abs(curY - yLast);
- xLast = curX;
- yLast = curY;
- if (xDistance > yDistance) {
- returnfalse;
- }
- }
- returnsuper.onInterceptTouchEvent(ev);
- }
- }
- 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
- *
- */
- publicclass 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
- publicboolean onInterceptTouchEvent(MotionEvent arg0) {
- // TODO Auto-generated method stub
- // 當攔截觸控事件到達此位置的時候,返回true,
- // 說明將onTouch攔截在此控制元件,進而執行此控制元件的onTouchEvent
- returntrue;
- }
- @Override
- publicboolean 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();
- returntrue;
- }
- }
- returnsuper.onTouchEvent(arg0);
- }
- /**
- * 單擊
- */
- publicvoid onSingleTouch() {
- if (onSingleTouchListener != null) {
- onSingleTouchListener.onSingleTouch();
- }
- }
- /**
- * 建立點選事件介面
- *
- * @author wanpg
- *
- */
- publicinterface OnSingleTouchListener {
- publicvoid onSingleTouch();
- }
- publicvoid setOnSingleTouchListener(
- OnSingleTouchListener onSingleTouchListener) {
- this.onSingleTouchListener = onSingleTouchListener;
- }
- }
- view.setFocusable(true);
- view.setFocusableInTouchMode(true);
- view.requestFocus();