作者在編寫一個(gè)文章編輯頁面阐斜,效果圖如下:
在完成Beta版本之后,被要求增加一個(gè)小需求煤杀,要求在切換頁面的時(shí)候眷蜈,必須對原來頁面的內(nèi)容進(jìn)行判斷,如果頁面沒有內(nèi)容怜珍,那么直接切換過去端蛆;假如原頁面含有內(nèi)容,需要彈出一個(gè)對話框酥泛,讓用戶二次確認(rèn)今豆。效果如下:
由于UI上有對兩個(gè)Title下劃線指示器長短的要求,所以采用了ViewPager+RadioGroup來實(shí)現(xiàn)這個(gè)頁面柔袁。
關(guān)于如何自定義實(shí)現(xiàn)指示器長度呆躲,作者采用的是RadioGroup,通過修改背景來實(shí)現(xiàn)捶索。
背景實(shí)現(xiàn)可以參考另一篇文章:
Shape為View定制下劃線
也通過其它方式去修改Title下劃線指示器的文章:
Android 自定義ViewPager下劃線指示器Indicator長度
本篇文章的重點(diǎn)不是在此插掂,便不再細(xì)說。
為了能切換的時(shí)候腥例,彈出確認(rèn)框辅甥。作者給每一個(gè)RadioButton增加點(diǎn)擊監(jiān)聽:
opinionRadioButton.setOnClickListener {
if(頁面是否有輸入內(nèi)容){
彈出切換確認(rèn)對話框
}else{
直接切換過去
}
}
運(yùn)行之后,發(fā)現(xiàn)頁面毫無波瀾燎竖。代碼沒有執(zhí)行OnClickListener里面的onClick方法璃弄。事件被消費(fèi)掉了,沒有下發(fā)到RadioButton的OnClickListener构回。
所以夏块,問題的核心就是截取點(diǎn)擊事件疏咐,不能讓RadioButton或者RadioGroup消費(fèi)掉,我們要自己決定是否消費(fèi)掉這個(gè)事件脐供。
了解事件分發(fā)的原理浑塞,我們都知道,事件分發(fā)都是從上層交給下層進(jìn)行的政己。也就是容器類ViewGroup首先會將事件分發(fā)給下面的子View酌壕,如果子View不處理,ViewGroup才去處理匹颤。
而截取事件仅孩,就是要打斷事件下發(fā)的流程。按照業(yè)務(wù)邏輯印蓖,那就是頁面內(nèi)容決定了是否攔截辽慕。
這樣看起來,思路就簡單多了赦肃。在RadioGroup判斷是否攔截事件溅蛉,如果需要攔截,那么自身消費(fèi)掉他宛。
需要自定義一個(gè)RadioGroup船侧,重寫onInterceptTouchEvent方法,控制RadioGroup是否消費(fèi)事件厅各。
public class InterceptRadioGroup extends RadioGroup {
private InterceptListener externalListener;
public InterceptRadioGroup(Context context) {
super(context);
}
public InterceptRadioGroup(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
if (externalListener != null) {
if (externalListener.onExternalIntercept(ev)) {
return true;
}
return super.onInterceptTouchEvent(ev);
}
return super.onInterceptTouchEvent(ev);
}
public View findViewByXY(float x, float y) {
View v = null;
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
Rect rect = new Rect(child.getLeft(), child.getTop(), child.getRight(), child.getBottom());
if (!rect.contains((int) x, (int) y)) {
continue;
}
v = child;
break;
}
return v;
}
public void setExternalListener(InterceptListener externalListener) {
this.externalListener = externalListener;
}
public interface InterceptListener {
boolean onExternalIntercept(MotionEvent ev);
}
}
定義一個(gè)InterceptListener接口镜撩,里面只有一個(gè)回調(diào)方法onExternalIntercept,返回true則表示消費(fèi)掉這個(gè)事件队塘。onInterceptTouchEvent的核心就是調(diào)用這個(gè)方法來決定是否繼續(xù)下發(fā)事件袁梗,以此打斷RadiaoGroup的切換。
具體實(shí)現(xiàn):
typeRadioGroup.setExternalListener(object : InterceptRadioGroup.InterceptListener {
override fun onExternalIntercept(ev: MotionEvent?): Boolean {
//如果頁面沒有內(nèi)容不攔截憔古,isNOtInterceptEvent()是true,onExternalIntercept返回false
if (isNOtInterceptEvent()) {
return false;
}
var result = false
ev?.let {
//判斷點(diǎn)擊到哪個(gè)Button
val view = typeRadioGroup.findViewByXY(ev.x, ev.y)
if (view is RadioButton) {
val button = view as RadioButton
//過濾重復(fù)點(diǎn)擊
if (button.isChecked) {
result = false
} else {
//彈出確認(rèn)框,onExternalIntercept返回true遮怜,不讓事件繼續(xù)下發(fā)
val switchDialog = BaseRemindDialog.Build(this@EditArticleActivity)
.setTitle(getString(R.string.dialog_title_tip))
.setContent(getString(R.string.text_ensure_switch_edit))
.setLeftBtn(getString(R.string.text_cancel))
.setRightBtn(getString(R.string.text_confirm))
.setRightColor(ContextCompat.getColor(this@EditArticleActivity, R.color.text_color_black))
.setListent(object : BaseRemindDialog.OnClickListent {
override fun onLeftClick() {
}
override fun onRightClick() {
//事件已經(jīng)被消費(fèi)了,需要手動去修改RadioButton的選中狀態(tài)
typeRadioGroup.check(view.id)
}
}).build()
switchDialog.show()
}
result = true
} else {
result = false
}
}
return result
}
})