自定义控件-侧边菜单SlidingMenu(滑动菜单)
1.布局
?activity_main.xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.example.slidemenu.MainActivity" > <com.example.slidemenu.SlideMenuandroid:id="@+id/sm"android:layout_width="match_parent"android:layout_height="match_parent" >? <!--?引入菜單布局,?索引為:?0?-->
? ? ? ??<include layout="@layout/slide_menu" />
? <!--?引入菜單布局,?索引為:?0?-->
<include layout="@layout/slide_content" /></com.example.slidemenu.SlideMenu></RelativeLayout>這個(gè)布局文件用到了自定義的ViewGroup對(duì)象com.example.slidemenu.SlideMenu,
繼承了ViewGroup類的控件時(shí)可以在其內(nèi)部嵌套子控件。
slide_content.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical" ><LinearLayout android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="horizontal"android:background="@drawable/top_bar_bg"android:gravity="center_vertical"><ImageViewandroid:id="@+id/iv" android:layout_width="wrap_content"android:layout_height="wrap_content"android:background="@drawable/main_back"/><TextView android:layout_width="1dp"android:layout_height="match_parent"android:background="@drawable/top_bar_divider"android:layout_margin="5dp"/><TextView android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="新聞"android:textSize="30sp"android:textColor="#ffffff"/></LinearLayout><TextView android:layout_width="match_parent"android:layout_height="match_parent"android:textSize="30sp"android:text="!!!!!!!!!!!"android:gravity="center"/> </LinearLayout>slide_menu.xml
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="240dp"android:layout_height="match_parent" ><LinearLayoutandroid:layout_width="240dp"android:layout_height="match_parent"android:background="@drawable/menu_bg"android:orientation="vertical" ><TextView android:text="新聞"android:drawableLeft="@drawable/tab_news"style="@style/SlideMenuStyle"/><TextView android:text="訂閱"android:drawableLeft="@drawable/tab_read"style="@style/SlideMenuStyle"/><TextView android:text="本地"android:drawableLeft="@drawable/tab_local"style="@style/SlideMenuStyle"/><TextView android:text="跟帖"android:drawableLeft="@drawable/tab_ties"style="@style/SlideMenuStyle"/><TextView android:text="圖片"android:drawableLeft="@drawable/tab_pics"style="@style/SlideMenuStyle"/><TextView android:text="話題"android:drawableLeft="@drawable/tab_ugc"style="@style/SlideMenuStyle"/><TextView android:text="投票"android:drawableLeft="@drawable/tab_vote"style="@style/SlideMenuStyle"/><TextView android:text="聚合閱讀"android:drawableLeft="@drawable/tab_focus"style="@style/SlideMenuStyle"/></LinearLayout></ScrollView>/res/values/styles.xml
<resources><style name="AppBaseTheme" parent="Theme.AppCompat.Light"></style><!-- Application theme. --><style name="AppTheme" parent="AppBaseTheme"></style> <!-- slideMenu style --><style name="SlideMenuStyle"><item name="android:layout_width">match_parent</item><item name="android:layout_height">wrap_content</item><item name="android:gravity">center_vertical</item><item name="android:textSize">18sp</item><item name="android:textColor">#ffffff</item><item name="android:background">@drawable/selector_slidemenuitem_bg</item><item name="android:padding">10dp</item><item name="android:drawablePadding">20dp</item><item name="android:onClick">click</item><item name="android:clickable">true</item></style></resources>res/drawable-hdpi/selector_slidemenuitem_bg.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android" > <!-- @android:color/transparent為透明色 --><item android:drawable="@android:color/transparent" android:state_pressed="true"></item><item android:drawable="@color/slidemenu_press_bg" android:state_pressed="false"></item></selector>res/values/colors.xml
<?xml version="1.0" encoding="utf-8"?> <resources><color name="slidemenu_press_bg">#3333cccc</color> </resources>?
業(yè)務(wù)邏輯實(shí)現(xiàn)
?
自定義ViewGroup控件
?
?Android事件處理機(jī)制
--------------------------------------------------
自定義類SlideMenu繼承ViewGroup。該類作為自定義控件類。
SlideMenu.java
package com.example.slidemenu;import android.content.Context; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewGroup; import android.widget.Scroller;public class SlideMenu extends ViewGroup {private int downX;// 按下時(shí)x軸的偏移量private int menuMeasuredWidth;int currentState = STATE_MAIN_VIEW;// 當(dāng)前屏幕顯示的界面, 默認(rèn)為: 主界面static final int STATE_MENU_VIEW = 0;// 菜單界面static final int STATE_MAIN_VIEW = 1;// 主界面// 利用這個(gè)對(duì)象做出滑動(dòng)的動(dòng)畫(huà)效果 Scroller scroller;public SlideMenu(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubscroller = new Scroller(context);}// 測(cè)量子節(jié)點(diǎn)的大小/*** widthMeasureSpec 填充屏幕 heightMeasureSpec 填充屏幕*/@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {// TODO Auto-generated method stubsuper.onMeasure(widthMeasureSpec, heightMeasureSpec);// 調(diào)用子節(jié)點(diǎn)的measure方法,該方法實(shí)際是調(diào)用了子節(jié)點(diǎn)的onMeasure方法,測(cè)量子節(jié)點(diǎn)的大小// 測(cè)量菜單的寬和高. 寬: 240dip, 高: 填充屏幕View menuView = getChildAt(0);menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);// 測(cè)量主界面的寬和高. 寬: 填充屏幕, 高: 填充屏幕View mainView = getChildAt(1);mainView.measure(widthMeasureSpec, heightMeasureSpec);}// 分配空間// 因?yàn)閟lideMenu占滿了父元素,寬高與父元素相同// l:0// t:0// r:slideMenu的寬,也就是父元素的寬// b:slideMenu的高,也就是父元素的高 @Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {// TODO Auto-generated method stub// 主界面的位置放置在屏幕左上角View mainView = getChildAt(1);mainView.layout(l, t, r, b);// 把菜單的位置放置在屏幕的左側(cè)View menuView = getChildAt(0);menuMeasuredWidth = menuView.getMeasuredWidth();menuView.layout(-menuView.getMeasuredWidth(), t, 0, b);}@Overridepublic boolean onInterceptTouchEvent(MotionEvent ev) {// 只有在橫著滑動(dòng)時(shí)才可以攔截.switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:downX = (int) ev.getX();break;case MotionEvent.ACTION_MOVE:int moveX = (int) ev.getX();if (Math.abs(moveX - downX) > 10) {return true;}break;}return super.onInterceptTouchEvent(ev);}@Overridepublic boolean onTouchEvent(MotionEvent event) {// TODO Auto-generated method stubswitch (event.getAction()) {case MotionEvent.ACTION_DOWN:downX = (int) event.getX();break;case MotionEvent.ACTION_MOVE:int moveX = (int) event.getX();int offsetX = downX - moveX;// 判斷一下用戶手指滑動(dòng)是否越界// 判斷給定當(dāng)前的增量移動(dòng)后, 是否能夠超出邊界.int scrollX = getScrollX();if (scrollX + offsetX < -menuMeasuredWidth) {// 當(dāng)前超出了左邊界, 應(yīng)該設(shè)置為在菜單的左邊界位置上.scrollTo(-menuMeasuredWidth, 0);} else if (scrollX + offsetX > 0) {// 當(dāng)前超出了右邊界, 應(yīng)該設(shè)置為0scrollTo(0, 0);} else {scrollBy(offsetX, 0);}downX = moveX;break;case MotionEvent.ACTION_UP:// 獲取菜單寬度的一半int center = -menuMeasuredWidth / 2;scrollX = getScrollX();// 當(dāng)前屏幕左上角的值if (scrollX < center) {currentState = STATE_MENU_VIEW;refreshViewState();} else {currentState = STATE_MAIN_VIEW;refreshViewState();}break;}return true;}// 松手時(shí)根據(jù)滑動(dòng)進(jìn)度,讓mScrollX復(fù)位/*** 根據(jù)currentScreen變量來(lái)切換屏幕顯示*/private void refreshViewState() {// TODO Auto-generated method stubint startX = getScrollX();// 開(kāi)始的位置int dx = 0;// 增量值 = 目的地位置 - 開(kāi)始的位置;if (currentState == STATE_MAIN_VIEW) {dx = 0 - startX;} else if (currentState == STATE_MENU_VIEW) {dx = -menuMeasuredWidth - startX;}int duration = Math.abs(dx) * 10;if (duration > 1600) {duration = 1600;}// arg0:滑動(dòng)的開(kāi)始坐標(biāo)// arg1:滑動(dòng)的距離scroller.startScroll(startX, 0, dx, 0, duration);// 只要調(diào)用invalidate,那么computeScroll方法就會(huì)調(diào)用// 刷新當(dāng)前控件, 會(huì)引起onDraw方法的調(diào)用.invalidate();// -> drawChild -> view.draw -> view.computeScroll }@Overridepublic void computeScroll() {// scroller不會(huì)去改變mScrollX的值,它只是幫你計(jì)算出你應(yīng)該把mScrollX的值變?yōu)槎嗌?/span>// 判斷動(dòng)畫(huà)是否結(jié)束,如果時(shí)間到了,那么結(jié)束了,返回false,如果時(shí)間未到,返回trueif (scroller.computeScrollOffset()) {// 當(dāng)前mScrollX應(yīng)該變?yōu)槎嗌?#xff0c;這個(gè)返回值是startX+應(yīng)該位移的距離/** scroller .startScroll(0 , 0 , 1000, 0,100);* * 當(dāng)時(shí)間過(guò)去了1毫秒時(shí),屏幕應(yīng)該移動(dòng)10像素 當(dāng)時(shí)間過(guò)去了10毫秒時(shí),屏幕應(yīng)該移動(dòng)100像素 例如:* 3點(diǎn)10分50000毫秒,調(diào)用那個(gè)了scroller.startScroll(0 , 0 , 1000, 0,100);* 3點(diǎn)10分50010毫秒,調(diào)用那個(gè)了scroller.getcurrx(),返回100* 3點(diǎn)10分50050毫秒,調(diào)用那個(gè)了scroller.getcurrx(),返回500*/int currX = scroller.getCurrX();scrollTo(currX, 0);invalidate();// 在觸發(fā)當(dāng)前方法, 相當(dāng)于遞歸. }}/*** 是否顯示菜單* * @return true 顯示菜單, false 不顯示*/public boolean isShowMenu() {return currentState == STATE_MENU_VIEW;}/*** 隱藏菜單*/public void hideMenuView() {currentState = STATE_MAIN_VIEW;refreshViewState();}/*** 顯示菜單*/public void showMenuView() {currentState = STATE_MENU_VIEW;refreshViewState();} }MainActivity.xml
package com.example.slidemenu;import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.View; import android.view.View.OnClickListener; import android.view.Window; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast;public class MainActivity extends ActionBarActivity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);requestWindowFeature(Window.FEATURE_NO_TITLE);setContentView(R.layout.activity_main);final SlideMenu sm = (SlideMenu) findViewById(R.id.sm);ImageView iv = (ImageView) findViewById(R.id.iv);iv.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {// 判斷當(dāng)前狀態(tài)if (sm.isShowMenu()) {// 是菜單界面, 切換到主界面 sm.hideMenuView();} else {// 是主界面, 應(yīng)該把菜單顯示出來(lái) sm.showMenuView();}}});}public void click(View v) {Toast.makeText(this, ((TextView) v).getText(), 0).show();}}?
轉(zhuǎn)載于:https://www.cnblogs.com/crazyzx/articles/5545970.html
總結(jié)
以上是生活随笔為你收集整理的自定义控件-侧边菜单SlidingMenu(滑动菜单)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: PAT 甲级 1027 Colors i
- 下一篇: UNIX环境高级编程 文件I/O