Android開發中,如何有效解決ScrollView和ListView衝突?
還有ViewPager GridView 感覺資料很少 而且大多是用了無效的。。
——————————————————————————————謝謝各位熱心的答主解答!我確實有點沒描述清楚,其實主要是滑動的衝突,雖然是看過一些事件分發的處理,但項目遇到問題感覺還是解決不了。拿我最近的一個項目來說吧,進到主頁以後是可以左右滑動的,大家肯定都會想到側滑菜單SlidingMenu,那麼問題來了,產品要求左右的頁面是可以全屏的。。而通過我初步的使用以及去網上查資料,SlidingMenu的左右菜單全屏之後就不能滑動了,那麼我只能是監聽左右頁面的onTouch事件,問題又來了。。因為右邊的頁面又有一個ScrollView,是一些功能的菜單,點擊之後要跳轉到對應的界面,那麼肯定要有onClick事件,然而右界面已經有了onTouch且返回值是true,onClick又掛掉了。。改了一會onClick能用了,ScrollView又不能上下滑動了。。各種蛋疼
這個很常見,比如出門左轉打開企鵝,QQ聊天記錄列表,縱滑翻過不同好記錄,橫滑刪除記錄。但兩者並不衝突。
一句話概括核心思想:有一個方法,在當前view中獲得ViewParent,並請求父容器(臨時)不要攔截觸摸事件,當某個觸摸事件處理完後,再恢復父容器能攔截。
這個方法是(需要自己在子View中實現):
當然,接下來需要重寫下listView中onTouchEvent()方法。
舉個例子:如果子View要檢測橫滑,父容器檢測縱滑,很分裂對吧?
解決方案是:
當子容器檢測到橫滑的時候,禁止本該要豎滑的父容器,等子容器的橫滑事件結束,再恢復回來即可(反過來也成立)。
光說不貼代碼是耍流氓,這裡我這寫了個小例子:
http://blog.csdn.net/oyyj42/article/details/47333443仔細看下這個方法
事實證明,還是有地方用的到的
~~我是分割線~~
雖然onTouchEvent可以解決,不過我真的不知道除了教學視頻以外哪裡還會遇到類似的嵌套情況不要拿 ScrollView 嵌套 ListView 啊。你為什麼要這麼做呢?
監聽scroll,配合好onIntercept
題主只需要看一下Android的touch事件分發和攔截機制即可
恕我直言,感覺樓主的標題和問題描述牛頭不對馬嘴啊,身為程序員,樓主的邏輯思維和整理能力有待加強。。仔細看了下你的描述,這個問題應該也不算什麼特麻煩的事兒,自定義右側頁面根布局的ViewGroup,重寫onInterceptTouchEvent方法,如果是橫向滑動這個事件就攔截掉自己處理,否則super.onIn....
ListView 和 ScrollView 的衝突真的是一個大問題。包括使用RecyclerView 也一樣會遇到這個問題。我們的 Android開發者納米學位的第二個項目,就要實現電影詳情信息的展示。 應用需要在一個 Activity 中展示電影劇情,若干個預告片,以及若干個評論。如下圖所示。
於是問題就來了,若干個要告片,若干個評論,如何展示在一個可以豎直滑動的界面裡面呢?
下面是我們的一個學員 AL-Arx7 經過自己的研究以後,發出的總結帖。特別分享給大家。
TL;DR: 重寫ListView 的 onMeasure方法,使Listview以為自己的高度很高很高,從而永遠不會滑動。 缺點:Listview 過長是非常影響性能。
---------------------------------------------------------------------------------------------因為在電影的詳細界面中,內容太多導致無法,除了電影本身的信息外,還用到了兩個listview來顯示預告片與評論,所以最開始考慮在外層加入了一個ScrollView來顯示全部內容。 然後,抬頭就發現自己已經在一個大坑中。
明明感覺挺常用的格式居然有各種問題,ScrollView和listview 存在衝突。雖然ScrollView能讓我拉動屏幕看到更多,如但果在ScrollView中使用listview,就算listview中用adapter塞入了多份數據 也就只會顯示一份。 stackoverflow上各種吐槽和解決方法,就是不存在myListView.scrollEnabled = false;這樣簡單的方式。
消耗了我不少時間來找到一種合適的方法。作為紀念就把我找到,並且測試過的幾種方法大致說明下。
1.手動設置ListView的高度layout_height如果手動設置 ListView的高度使之大於等於內容所需的高度就不會被收縮,符合我的要求,但是問題是如何自適應內容的高度。 stackoverflow上有人給出這樣的解決方法,調用靜態函數計算內容數量手動設置ListView的高度。
好處:簡單,不需要做XML上的修改。
壞處:對布局之類的限制較大只能 LinearLayout
注意事項: 雖然按照給出方法的大神要求:在設置Adapter之後調用;子控制項的布局為LinearLayout;但是 listAdapter.getCount會是0.因為還沒有數據。 因此我嘗試在onLoaderFinish 的swap之後調用,確實能實現,能開心的拉動了。 但是可能是高度計算上有缺陷 如果Listview中如果是TextView 且為多行,還是可能會出現被收縮的情況。如果哪位知道怎麼做請告訴我下。
public class Utility {
public static void setListViewHeightBasedOnChildren(ListView listView) {
ListAdapter listAdapter = listView.getAdapter();
if (listAdapter == null) {
return;
}
int totalHeight = listView.getPaddingTop() + listView.getPaddingBottom();
for (int i = 0; i &< listAdapter.getCount(); i++) { View listItem = listAdapter.getView(i, null, listView); if (listItem instanceof ViewGroup) { listItem.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)); } listItem.measure(0, 0); totalHeight += listItem.getMeasuredHeight(); } ViewGroup.LayoutParams params = listView.getLayoutParams(); params.height = totalHeight + (listView.getDividerHeight() * (listAdapter.getCount() - 1)); listView.setLayoutParams(params); } }
2.用 listview/recyclerview 代替ScrollView
將整個界面分成數塊。 以這個詳細頁面為例,電影的標題,日期,概述之類做一個XML, R.layout.Detailitem1; 預告片列表做一個XML R.layout.Detailitem2; 評論列表做一個XML R.layout.Detail_item3; 之後就類似Sunshine應用中 給ListView做adapter時候,根據類別導入不同的布局。
在 adapter中添加類別
private static final int VIEW_TYPE_Item1 = 1;
private static final int VIEW_TYPE_Item2 = 2;
private static final int VIEW_TYPE_Item3 = 3;
private static final int VIEW_TYPE_Count = 3; //類型數
實現 getItemViewType getViewTypeCount cursorAdapter中就是在newView方法中new方法中根據類別 LayoutInflater.from(context).inflate( R.layout.Detail_itemX, parent, false); 即可
好處:迴避了坑人的衝突問題。
壞處:好好的一個界面被拆成了好多塊,adapter的複雜度高了不少。
stackoverflow上找到的另外種迴避的方法,原先的 ListView既然會衝突,那就自定義一個屏蔽衝突的。 重寫了 onMeasure 方法,修改了原版傳遞進入的heightMeasureSpec參數。 用 MeasureSpec.makeMeasureSpec 方法,以 AT_MOST 模式獲取了一個相當大的值,保證子類都能顯示出來。
好處:簡單,非常簡單。無論基於代碼量,還是修改難度。如果沒出現 myListView.scrollEnabled = false這樣的功能我應該就用這招了。
壞處:額,找到太遲浪費不少時間
MeasureSpec.AT_MOST:子視圖的大小最多是specSize中指定的值,也就是說不建議子視圖的大小超過specSize中給定的值。
import android.content.Context;
import android.util.AttributeSet;
import android.widget.ListView;
public class UnScrollListView extends ListView {
public UnScrollListView(Context context) {
super(context);
}
public UnScrollListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public UnScrollListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE &>&> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
按照@Walker 導師建議,做了下這個方法的測試。找到兩種方式實現。
方法1:手動添加
LinearLayout linearLayout = (LinearLayout) findViewById(...);
LayoutInflater inflater = LayoutInflater.from(this);
for (item in arrayList) {
View view = inflater.inflate(R.layout.row, linearLayout, false);
// set item content in view
linearLayout.addView(view)}
這種方法只適合非常簡單的情況。看著有點蠢。
方法2:
給LinearLayout 一個adapter 我想找一個實現了CursorAdapter的LinearLayout 網上幾乎沒有。 下面的程序最多算是實驗性質,完全不能用問題很多。 看了下android的源碼,這個不僅沒有實現recycling,連OnItemClickListener都沒有實現。 使用後顯示一份數據,效果也有問題。 查看了源碼中的ItemClick事件也在別的類中實現。感覺要實現一個cursorAdapter需要實現不少東西的樣子。 不能多個繼承多個類好難受。花了這麼多時間搞不定,不開心啊。暫時繼續使用方法三自定義listView的方法處理。
參考資料:Stack Overflow 上的解決方案
四種方案解決ScrollView嵌套ListView問題
去掉ScrollView,把其他布局都放在ListView的header和footer中。
還在用ScrollView和ListView?NestedScrollView 和 RecyclerView 不更好?
也經常會看到這樣的提問,我的第一感覺是你的布局寫錯了,我從來沒有遇到過scrollview和listview嵌套的問題,因為不需要這樣的界面,要麼用scrollview要麼用listview要麼用recyclerview,除非方向不同,否則沒有共存的需要!
不要嵌套。
我記得stackoverflow上有個比較絕好的解決方案,那就是用linearlayout代替listview,上github上搜索linearlistview
slidingmenu的bug我已解決,歡迎查看我的博客,衝突的話自定義一個listview就可以啦附上github地址,有詳細的博客加以講解 https://github.com/Mr-wangyong/slidingMenu.git
[Android]ScrollView,ListView,ExpandableListView,ViewPager各種嵌套demo
自定義listview /重寫on measure等方法 百度幾行代碼幫你搞定
一開始我看成布局衝突了,按題主的意思應該是事件衝突,子類試試調用這個方法:
requestDisallowInterceptTouchEvent(boolean b);
-------原回答
重寫ListView或GridView的onMeasure方法,在調用父類之前加上這一句,就可以放到ScrollView裡面去了。
heightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE &>&> 2, MeasureSpec.AT_MOST);
@sbbic 說的android的touch事件分發機制,這裡有一些資料講得都很詳細了。
Android ViewGroup攔截觸摸事件詳解@hi大頭鬼hi 說的可以參看一個下拉刷新的例子,關於scroll和onIntercept中的一些相關應用
打造通用的Android下拉刷新組件(適用於ListView、GridView等各類View)可能還會有一些ListView在Scrollview中無法顯示全的問題,和 @清沙 說的相關,在stackoverflow上有個解決方案,是把ListView中的所有Item的高度計算出來,不過這樣性能不好。
android - How can I put a ListView into a ScrollView without it collapsing?這些是當時我在做項目時幫助我解決關於這個問題的資料,應該可以解決大部分題主會遇到的問題吧。推薦閱讀:
※關於 Android,用多個 activity,還是單 activity 配合 fragment?
※怎麼可以快速的學會並掌握Android開發?
※有哪些開源的採用 Material Design 的 Android 程序呢?
※移動APP切圖標準?
※學習android架構的步驟?