開篇
新的項目中有一個很長的資料提交和資料查看頁面,爲了方便查看,上方加了 RadioGroup 分類標籤,可以快速滑動的相應位置。
實現的效果和下面差不多,其實,蘑菇街的商品詳情也是這樣實現的。
實現思路
-
RadioGroup + ScrollView 控件搭配實現
-
RadioGroup 的 OnCheckedChangeListener 監聽事件中拿到 RadioButton 對應的內容 Y 座標,通過 scrollTo(0,Y)或者 smoothScrollTo(0,Y) 控制 ScrollView 的滑動。
-
ScrollView 的 onScrollChanged 方法中通過 Y 值判斷範圍,來確定選中哪個 RadioButton 。
始料未及的小問題 & 解決方法
上面的步驟是不是看起來是不是超級簡單,然而事實證明,too young to naive !
1.OnCheckedChangeListener 和 onScrollChanged 會互相觸發吶吶吶,下滑時還好,上滑的時候,標籤直接會連續選中到第一個。
2.被上滑時不受控制的 ScrollView 折磨得幾乎要瘋的我,發現是 RadioGroup 的鍋,這貨的 onCheckedChanged 一次觸發會調用多次。
OnCheckedChangeListener 和 onScrollChanged 會互相觸發
實話說,這是非常正常的表現,畢竟是需要相互聯動的兩個控件,就是聯動的時機有誤,需要我們來手動控制一下。
現狀:
點擊 RadioGroup ,ScrollView 滑動到固定位置,上滑不會有問題,下滑時由於判斷條件不同,ScrollView 滑動到固定位置時會觸發 RadioGroup 的監聽事件。
需求:
RadioGroup 觸發的時候,,ScrollView 中對 RadioGroup 就不要觸發。
ScrollView 聯動觸發 RadioGroup 的時候,RadioGroup 對 ScrollView 的聯動不要觸發。
簡單來說,就是雙向同時聯動改成雙向不同時聯動。
修改方法:
1.添加兩個變量:
boolean isScrollFlag = false ;
boolean isRadioFlag = false;
2.RadioGroup 的 onCheckedChanged 中的判斷:
//攔截 scrollView 中的聯動觸發
if(isScrollFlag){
isScrollFlag = isRadioFlag = false;
return;
}
3.ScrollView 的 onScrollChanged 中的判斷:
//攔截 radioGroup 選中的聯動觸發
if(isRadioFlag ){
Log.d(TAG, "onScrollChanged: 攔截");
isRadioFlag = isScrollFlag = false;
return;
}
RadioGroup 調用check()方法 onCheckedChanged 一次觸發多次調用的問題。
多次觸發是 check() 中多次調用了 setCheckedId() 方法,而 setCheckedId() 裏面又有多次調用 onCheckedChanged 。以上這句話的具體細節請自行查看相關源碼。這裏放上我的解決方法:
在 RadioGroup 的 onCheckedChanged 方法里加入如下代碼:
mRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
@Override
public void onCheckedChanged(RadioGroup group, int checkedId) {
//防止onCheckedChanged 被調用多次
View viewById = mRadioGroup.findViewById(checkedId);
if (!viewById.isPressed()){
Log.w(TAG, "onCheckedChanged: 阻止");
return;
}
//...
}
});
最後
本來想按照實現步驟一步步附上上對應的代碼的,後來想想也不是很有必要,還是思路說清楚比較重要,最後附上完整代碼鏈接。
發現一個待改進的問題,就是 scrollView 調用 smoothScrollTo(0,Y) 方法其實也是會多次觸發 onScrollChanged()。雖然最後實現了效果,但是總是有點不對的,這個問題後面會再優化。
技術粗淺,如果有不對的地方,還請留言告知。