Android實(shí)現(xiàn)滑動(dòng)側(cè)邊欄
在A(yíng)ndroid應(yīng)用開(kāi)發(fā)中,滑動(dòng)側(cè)邊欄經(jīng)常使用,今天我也試著自己進(jìn)行了一個(gè)簡(jiǎn)單的實(shí)踐,雖然功能還不是很強(qiáng)大,但是可以保留下來(lái)為以后的開(kāi)發(fā)使用,有需要時(shí)在進(jìn)行簡(jiǎn)單的修改。實(shí)現(xiàn)一個(gè)滑動(dòng)側(cè)邊欄思路也很簡(jiǎn)單:
1.重寫(xiě)一個(gè)SlidingMenu類(lèi)繼承ViewGroup,病危該ViewGroup添加兩個(gè)子布局,分別為菜單和主界面顯示;
2.為了得到一個(gè)滑動(dòng)的效果,選擇Scroller幫助我們實(shí)現(xiàn),配合ViewGroup下的computeScroll方法實(shí)現(xiàn)界面的更新;
3.利用一個(gè)boolean來(lái)記錄菜單是否打開(kāi),在菜單打開(kāi)的狀態(tài)下向右滑動(dòng)不會(huì)響應(yīng),在菜單關(guān)閉的情況向左滑動(dòng)不會(huì)響應(yīng);
4.為了得到一個(gè)良好的交互,我們可以為界面滑動(dòng)與手指移動(dòng)的距離定義一個(gè)比例,如每次觸摸事件發(fā)生,界面移動(dòng)的距離僅為手指移動(dòng)距離的一半;
下面是兩張效果圖,界面沒(méi)怎么布局,大家湊合看
SlidingMenu實(shí)現(xiàn)代碼:
package com.example.test; import android.content.Context; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller; public class SlidingMenu extends ViewGroup { private static final String TAG = SlidingMenu.class.getName(); private enum Scroll_State { Scroll_to_Open, Scroll_to_Close; } private Scroll_State state; private int mMostRecentX; private int downX; private boolean isOpen = false; private View menu; private View mainView; private Scroller mScroller; private OnSlidingMenuListener onSlidingMenuListener; public SlidingMenu(Context context, View main, View menu) { super(context); // TODO Auto-generated constructor stub setMainView(main); setMenu(menu); init(context); } private void init(Context context) { mScroller = new Scroller(context); } @Override protected void onLayout(boolean arg0, int l, int t, int r, int b) { // TODO Auto-generated method stub mainView.layout(l, t, r, b); menu.layout(-menu.getMeasuredWidth(), t, 0, b); } public void setMainView(View view) { mainView = view; addView(mainView); } public void setMenu(View view) { menu = view; addView(menu); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // TODO Auto-generated method stub super.onMeasure(widthMeasureSpec, heightMeasureSpec); mainView.measure(widthMeasureSpec, heightMeasureSpec); menu.measure(widthMeasureSpec - 150, heightMeasureSpec); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: mMostRecentX = (int) event.getX(); downX = (int) event.getX(); break; case MotionEvent.ACTION_MOVE: int moveX = (int) event.getX(); int deltaX = mMostRecentX - moveX; // 如果在菜單打開(kāi)時(shí)向右滑動(dòng)及菜單關(guān)閉時(shí)向左滑動(dòng)不會(huì)觸發(fā)Scroll事件 if ((!isOpen && (downX - moveX) < 0) || (isOpen && (downX - moveX) > 0)) { scrollBy(deltaX / 2, 0); } mMostRecentX = moveX; break; case MotionEvent.ACTION_UP: int upX = (int) event.getX(); int dx = upX - downX; if (!isOpen) {// 菜單關(guān)閉時(shí) // 向右滑動(dòng)超過(guò)menu一半寬度才會(huì)打開(kāi)菜單 if (dx > menu.getMeasuredWidth() / 3) { state = Scroll_State.Scroll_to_Open; } else { state = Scroll_State.Scroll_to_Close; } } else {// 菜單打開(kāi)時(shí) // 當(dāng)按下時(shí)的觸摸點(diǎn)在menu區(qū)域時(shí),只有向左滑動(dòng)超過(guò)menu的一半,才會(huì)關(guān)閉 // 當(dāng)按下時(shí)的觸摸點(diǎn)在main區(qū)域時(shí),會(huì)立即關(guān)閉 if (downX < menu.getMeasuredWidth()) { if (dx < -menu.getMeasuredWidth() / 3) { state = Scroll_State.Scroll_to_Close; } else { state = Scroll_State.Scroll_to_Open; } } else { state = Scroll_State.Scroll_to_Close; } } smoothScrollto(); break; default: break; } return true; } private void smoothScrollto() { int scrollx = getScrollX(); switch (state) { case Scroll_to_Close: mScroller.startScroll(scrollx, 0, -scrollx, 0, 500); if (onSlidingMenuListener != null && isOpen) { onSlidingMenuListener.close(); } isOpen = false; break; case Scroll_to_Open: mScroller.startScroll(scrollx, 0, -scrollx - menu.getMeasuredWidth(), 0, 500); if (onSlidingMenuListener != null && !isOpen) { onSlidingMenuListener.close(); } isOpen = true; break; default: break; } } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { scrollTo(mScroller.getCurrX(), 0); } invalidate(); } public void open() { state = Scroll_State.Scroll_to_Open; smoothScrollto(); } public void close() { state = Scroll_State.Scroll_to_Close; smoothScrollto(); } public boolean isOpen() { return isOpen; } public void setOnSlidingMenuListener( OnSlidingMenuListener onSlidingMenuListener) { this.onSlidingMenuListener = onSlidingMenuListener; } public interface OnSlidingMenuListener { public void open(); public void close(); } }
在MainActivity中進(jìn)行調(diào)用
package com.example.test; import android.os.Bundle; import android.support.v4.app.FragmentActivity; import android.view.LayoutInflater; import android.view.View; import android.view.View.OnClickListener; import android.widget.Button; public class MainActivity extends Activity { private Button openButton; private Button closeButton; private SlidingMenu mSlidingMenu; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); mSlidingMenu = new SlidingMenu(this, LayoutInflater .from(this).inflate(R.layout.fragment1, null), LayoutInflater .from(this).inflate(R.layout.fragment2, null)); setContentView(mSlidingMenu);//注意setContentView需要換為我們的SlidingMenu openButton = (Button) findViewById(R.id.button1); closeButton = (Button) findViewById(R.id.button_close); openButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub mSlidingMenu.open(); } }); closeButton.setOnClickListener(new OnClickListener() { @Override public void onClick(View arg0) { // TODO Auto-generated method stub mSlidingMenu.close(); } }); } }
更多關(guān)于滑動(dòng)功能的文章,請(qǐng)點(diǎn)擊專(zhuān)題: 《Android滑動(dòng)功能》
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
移動(dòng)端android上line-height不居中的問(wèn)題的解決
現(xiàn)在越來(lái)越多的移動(dòng)界面使用rem適配,最近發(fā)現(xiàn)了移動(dòng)端android上line-height不居中的問(wèn)題,今日就來(lái)介紹一下解決的方法,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2018-03-03深入android中The connection to adb is
本篇文章是對(duì)android中The connection to adb is down的問(wèn)題以及解決方法進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下2013-05-05Flutter app頁(yè)面路由以及路由攔截的實(shí)現(xiàn)
本篇介紹了介紹了Flutter如何使用路由來(lái)實(shí)現(xiàn)頁(yè)面的跳轉(zhuǎn),從而簡(jiǎn)化頁(yè)面之間的耦合,并可以實(shí)現(xiàn)路由攔截。2021-06-06Android App中ViewPager所帶來(lái)的滑動(dòng)沖突問(wèn)題解決方法
Android中我們經(jīng)常使用ViewPager配合Fragment實(shí)現(xiàn)視圖滑動(dòng),但在實(shí)際操作中又會(huì)經(jīng)常發(fā)生方向上的沖突問(wèn)題,這里我們就來(lái)總結(jié)一下Android App中ViewPager所帶來(lái)的滑動(dòng)沖突問(wèn)題解決方法:2016-06-06Android split分割特殊字符取名稱(chēng)的方法
這篇文章主要為大家詳細(xì)介紹了Android split分割特殊字符取名稱(chēng)的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-09-09Android實(shí)現(xiàn)上拉加載更多ListView(PulmListView)
這篇文章主要介紹了Android實(shí)現(xiàn)上拉加載更多ListView:PulmListView,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09關(guān)于Gradle下載失敗問(wèn)題的快速解決方法
這篇文章主要給大家分享了關(guān)于Gradle下載失敗問(wèn)題的快速解決方法,文中介紹了兩種解決方法,分別是使用已存在的gradle版本和手動(dòng)下載gradle,文中介紹的非常詳細(xì),需要的朋友們下面來(lái)一起看看吧。2017-05-05Android中使用ViewStub實(shí)現(xiàn)布局優(yōu)化
ViewStub是Android布局優(yōu)化中一個(gè)很不錯(cuò)的標(biāo)簽/控件,直接繼承自View。雖然Android開(kāi)發(fā)人員基本上都聽(tīng)說(shuō)過(guò),但是真正用的可能不多。今天我們就來(lái)詳細(xì)探討下ViewStub的使用2016-09-09