日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

自定义侧滑菜单

發(fā)布時(shí)間:2023/12/31 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 自定义侧滑菜单 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

同步發(fā)表于http://avenwu.net/customlayout/2014/12/16/sliding-menu/

Fork on github https://github.com/avenwu/support
無圖無真相,完整代碼

思路

從前兩年側(cè)滑菜單出現(xiàn)到火熱,到現(xiàn)在成為一種很常見的交互布局,作為開發(fā)者的我們其實(shí)選擇非常多了,既有開源的也有官方的。

  • Android support v4擴(kuò)展包的DrawerLayout
  • Android support v4擴(kuò)展包的SlidingPaneLayout
  • 比較知名的三方開源庫SlidingMenu
  • 其他...

這些控件的底層使用的技術(shù)實(shí)際上是類似的,為了更深入的悉知這些輪子是怎么造的,本文將著手實(shí)現(xiàn)一個(gè)簡易的側(cè)滑控件。

設(shè)計(jì)思路

首先可以一起分析一下,實(shí)現(xiàn)一個(gè)最基礎(chǔ)的菜單需要解決那些技術(shù)點(diǎn)。

  • 界面分為菜單區(qū)和內(nèi)容區(qū),通過滑動(dòng)顯示、隱藏菜單
  • 手勢分發(fā)處理
  • 根據(jù)滑動(dòng)停止后,根據(jù)位置自動(dòng)完成顯示、隱藏操作

實(shí)現(xiàn)細(xì)節(jié)

根據(jù)前面提到的幾個(gè)技術(shù)點(diǎn),現(xiàn)在開始逐一處理。

區(qū)域劃為

這里選擇FrameLayout作為基類,這樣可以免去處理菜單視圖和內(nèi)容視圖的層級(jí)關(guān)。

main = new FrameLayout(getContext()); main.setId(R.id.main); main.setLayoutParams(new FrameLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.MATCH_PARENT)); main.setBackgroundColor(getResources().getColor(android.R.color.holo_blue_bright)); addView(main);left = new FrameLayout(getContext()); left.setId(R.id.menu); left.setLayoutParams(new FrameLayout.LayoutParams(MENU_WIDTH, ViewGroup.LayoutParams.MATCH_PARENT)); addView(left);

手勢分發(fā)

手勢處理包括touch event分發(fā)和消耗,在onInterceptTouchEvent中可以簡單判斷當(dāng)前是否處于菜單滑動(dòng)狀態(tài),是的話攔截后續(xù)的手勢。

@Override public boolean onInterceptTouchEvent(MotionEvent ev) {if (!mSlidable) return false;final int action = ev.getAction();if (action != MotionEvent.ACTION_DOWN && isSliding) return true;switch (action) {case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:return false;case MotionEvent.ACTION_MOVE:if (Math.abs(ev.getX() - mSrcX) > touchSlop) {mSrcX = ev.getX();isSliding = true;}break;case MotionEvent.ACTION_DOWN:isSliding = false;mSrcX = ev.getX();break;}return isSliding; }

手勢處理

現(xiàn)在需要處理菜單的滑動(dòng)位置,在滑動(dòng)過程中,MotionEvent.ACTION_MOVE不斷被觸發(fā),所以可以在這里改變菜單view的位置,此處利用Scroller負(fù)責(zé)位置的變化;MotionEvent.ACTION_UP中判斷手勢抬起時(shí)的菜單位置狀態(tài),如果滑動(dòng)位置已經(jīng)達(dá)到菜單寬度的1/2,那么認(rèn)為菜單需要繼續(xù)打開,反之收起。

@Override public boolean onTouchEvent(MotionEvent event) {d("UIView", "event:" + event.toString());final int action = event.getAction();switch (action) {case MotionEvent.ACTION_DOWN:mSrcX = event.getX();break;case MotionEvent.ACTION_MOVE:int oldx = left.getScrollX();float dx = mSrcX - event.getX();if (dx != 0) {left.setVisibility(VISIBLE);float x = oldx + dx;d("onTouchEvent", "move, oldx=" + oldx + ", dx=" + dx + ", left=" +left.getLeft() + ", right=" + left.getRight() + ", getX=" + event.getX() + ", mSrcX=" + mSrcX);d("onTouchEvent", "before x=" + x);if (MENU_WIDTH < x) {x = MENU_WIDTH;}if (0 > x) {x = 0;}d("onTouchEvent", "after x=" + x);left.scrollTo((int) x, 0);mSrcX = event.getX();}break;case MotionEvent.ACTION_UP:int currentX = left.getScrollX();if (currentX + mSrcX - event.getX() >= MENU_WIDTH / 2.0) {int duration = (int) (Math.abs(MENU_WIDTH - currentX + 0.5f) / MENU_WIDTH * 1000);scroller.startScroll(currentX, 0, MENU_WIDTH - currentX, 0, duration);invalidate();} else {int duration = (int) (Math.abs(currentX + 0.5f) / MENU_WIDTH * 1000);scroller.startScroll(currentX, 0, 0 - currentX, 0, duration);invalidate();}break;case MotionEvent.ACTION_CANCEL:break;}return true; }

初始化視圖位置

除了手勢問題,還需要將視圖在容器中初始化位置,這里需要復(fù)寫onLayout,由于只有兩個(gè)子view(菜單區(qū),內(nèi)容區(qū)),默認(rèn)菜單處于關(guān)閉狀態(tài)。

@Override protected void onLayout(boolean changed, int left, int top, int right, int bottom) {int count = getChildCount();for (int i = 0; i < count; i++) {View child = getChildAt(i);if (child.getVisibility() == GONE) continue;final LayoutParams lp = (LayoutParams) child.getLayoutParams();if (child.getId() == R.id.menu) {final int childWidth = child.getMeasuredWidth();final int childHeight = child.getMeasuredHeight();int childLeft = 0;child.layout(childLeft, lp.topMargin, childLeft + childWidth, lp.topMargin + childHeight);child.scrollTo(MENU_WIDTH, 0);} else if (child.getId() == R.id.main) {child.layout(0, 0, child.getMeasuredWidth(), child.getMeasuredHeight());}} }

平滑滾動(dòng)

前面已經(jīng)提到改變菜單位置是利用了Scroller,主要是考慮到平滑滾動(dòng)問題。

@Override public void computeScroll() {d("computeScroll", "computeScroll");if (scroller.computeScrollOffset()) {int oldx = left.getScrollX();int x = scroller.getCurrX();d("computeScroll", "try scroll, oldx=" + oldx + ", x=" + x);if (oldx != x) {//this can only effect on the content view inside of leftleft.scrollTo(x, 0);left.invalidate();}invalidate();} else {scroller.abortAnimation();} }

小結(jié)

至此自定義一個(gè)簡易的側(cè)滑菜單涉及的主要技術(shù)點(diǎn)都解決了,其他細(xì)節(jié)可以看完整代碼

總結(jié)

以上是生活随笔為你收集整理的自定义侧滑菜单的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。