自定義ViewGroup之側滑選單

2021-09-11 09:06:03 字數 4063 閱讀 7319

最近pm2.5對側滑選單比較感興趣,很多頁面上都用到了側滑選單,之前也在網上看到了很多關於側滑,有自定義recyclerview,也有自定義item的,但是當自己真正去用的時候,發現有很多問題,所以打算自己參考網上的思路自己寫乙個,果然,看花容易繡花難,寫的很艱辛,不過最後還是實現了,下面看看效果圖:

側滑選單

下面簡單分享下實現的思路:

自定義viewgroup

這個其實沒什麼太多要說的,主要是有幾點需要注意下:

需要複寫三個layoutparams方法

generatedefaultlayoutparams

當動態向viewgroup中新增沒有引數的child的時候,會自動呼叫這個方法,將其設定成為預設的引數

generatelayoutparams(attributeset attrs)

根據布局中的屬性來生成layoutparams

generatelayoutparams(layoutparams layoutparams)

**中動態新增引數

2.在複寫onmeasure方法的時候,需要對wrapcontent這種情況進行特殊處理,因為很多時候item是包裹child的,高度並沒有固定死,所以需要特殊處理,不然會導致選單欄的內容高度顯示不正確處理的方式就是以第乙個child也就是內容區域為標準重新測量,**如下:

for (int i = 0; i < childcount; i++) 

if (i == 0) else

marginlayoutparams lp = (marginlayoutparams) child.getlayoutparams();

if (i > 0)

}複製**

3.onlayout

@override

protected void onlayout(boolean changed, int l, int t, int r, int b)

marginlayoutparams lp = (marginlayoutparams) mchild.getlayoutparams();

mleftoffset += lp.leftmargin;

topoffset += lp.topmargin;

int measuredwidth = mchild.getmeasuredwidth();

int measuredheight = mchild.getmeasuredheight();

mchild.layout(mleftoffset, topoffset, mleftoffset + measuredwidth, topoffset + measuredheight);

mleftoffset += (measuredwidth + lp.rightmargin);

topoffset = getpaddingtop();

}}複製**

截止到這裡,基本的measure跟layout就結束了,這個不是重點,重點在於解決滑動衝突。

view的滑動衝突

三個方法:

事件分發:public boolean dispatchtouchevent(motionevent ev)

touch 事件發生時 activity 的 dispatchtouchevent(motionevent ev) 方法會以隧道方式(從根元素依次往下傳遞直到最內層子元素或在中間某一元素中由於某一條件停止傳遞)將事件傳遞給最外層 view 的 dispatchtouchevent(motionevent ev) 方法,並由該 view 的 dispatchtouchevent(motionevent ev)方法對事件進行分發。dispatchtouchevent 的事件分發邏輯如下:

如果當前 view 獲取的事件直接來自 activity,則會將事件返回給 activity 的 ontouchevent 進行消費;

如果當前 view 獲取的事件來自外層父控制項,則會將事件返回給父 view 的 ontouchevent 進行消費。

事件攔截:public boolean onintercepttouchevent(motionevent ev)

在外層 view 的 dispatchtouchevent(motionevent ev) 方法返回系統預設的 super.dispatchtouchevent(ev) 情況下,事件會自動的分發給當前 view 的 onintercepttouchevent 方法。onintercepttouchevent 的事件攔截邏輯如下:

事件響應:public boolean ontouchevent(motionevent ev)

在 dispatchtouchevent 返回 super.dispatchtouchevent(ev) 並且 onintercepttouchevent 返回 true 或返回super.onintercepttouchevent(ev) 的情況下 ontouchevent 會被呼叫。ontouchevent 的事件響應邏輯如下:

● 如果事件傳遞到當前 view 的 ontouchevent 方法,而該方法返回了 false,那麼這個事件會從當前 view 向上傳遞,並且都是由上層 view 的 ontouchevent 來接收,如果傳遞到上面的 ontouchevent 也返回 false,這個事件就會「消失」,而且接收不到下一次事件。

● 如果返回了 true 則會接收並消費該事件。

● 如果返回 super.ontouchevent(ev) 預設處理事件的邏輯和返回 false 時相同。

需要注意的是view是沒有onintercepttouchevent這個方法,只能分發,不存在攔截,只能分發,就跟view沒有layout方法是一樣的道理。

通過上面的分析,我們需要在onintercepttouchevent中進行攔截,然後在ontoucheevent中進行處理

onintercepttouchevent

@override

public boolean onintercepttouchevent(motionevent ev) else

break;

case motionevent.action_up:

if (isopened && ev.getx() < getwidth() - getscrollx())

break;

}minterpoint.set(ev.getrawx(), ev.getrawy());

mtouchpoint.set(ev.getrawx(), ev.getrawy());

return consume;

}複製**

ontouchevent

public boolean ontouchevent(motionevent ev)  else 

break;

case motionevent.action_up:

case motionevent.action_cancel:

mvelocitytracker.computecurrentvelocity(1000, mmaxvelocity);

float velocityx = mvelocitytracker.getxvelocity(mpointerid);

if (math.abs(velocityx) > 1000) else

releasevelocitytracker();

break;

}mtouchpoint.set(ev.getrawx(), ev.getrawy());

return

true;

}複製**

ontouchevent就顯得有些麻煩

移動的方式

開啟選單

private void openmenu

() 複製**

關閉選單

private void closemenu

() 複製**

viewgroup自定義元件 側滑元件

繼承viewgroup製作的自定義元件常常是一些布局或者組合元件 和view的自定義元件類似,需要重寫onmeause和onlayout測量元件的寬高和布局,因為viewgruop裡面包含了子元件,所有在測量和定位的時候都是以子元件為中心進行測量和定位 不需要重寫ondraw方法,因為viewgro...

angularJs自定義實現側滑指令

老樣紙,先上圖 先上 html模板 div class div class slide item ref slide div class content ref content div ng transclude content div div div class side ref side div...

自定義ViewGroup(一)

1 概述 viewgroup是乙個view的容器,他可以給出childview的測量模式和測量其寬高,他的作用非常重要。childview測量模式 exactly 表示設定了精確的值,一般當childview設定其寬 高為精確值 match parent時,viewgroup會將其設定為exactl...