仿网易菜单 实现侧滑 SlidingMenu
不知不觉已经工作一个月了,时间过的真快,提早一年步入社会,心里感触还是挺大了,所有的一切都没有了在学校的那种感觉 .....
废话不多说,在公司做android的时候用到这个侧滑,公司里用的是开源框架,SlidingMenu,自己也尝试着去引用,感觉自己基础不好,实现起来十分费劲。
无意之中,发现黑马老师的视频里有这个就听了下,基本照写了一遍,代码就放在这里,方便自己查看,复习,也方便像我这样的android小白,来研究学习。
主界面:
package com.tai.dandelion; import com.tai.dandelion.view.SlideMenu; import android.os.Bundle; import android.app.Activity; import android.view.KeyEvent; import android.view.Menu; import android.view.View; import android.view.View.OnClickListener; import android.view.ViewGroup; import android.view.Window; import android.widget.ImageView; import android.widget.TextView; import android.widget.Toast; public class MainActivity extends Activity implements OnClickListener { private SlideMenu viewGroup;//这就是下面自定义ViewGroup private ImageView slidingmenu; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); //去除标题 一定要在setContentView之前 requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); viewGroup = (SlideMenu) findViewById(R.id.slidmenu); slidingmenu = (ImageView) findViewById(R.id.iv_slidmenu_back); slidingmenu.setOnClickListener(this); } @Override public void onClick(View v) { switch (v.getId()) { case R.id.iv_slidmenu_back: if(viewGroup.isShow()) { viewGroup.showMenu(); } else { viewGroup.hideMenu(); } break; default: break; } } @Override public boolean onKeyDown(int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_MENU) { if(viewGroup.isShow()) { viewGroup.showMenu(); } else { viewGroup.hideMenu(); } return true; } return super.onKeyDown(keyCode, event); } //菜单的点击事件,在与布局文件中对应,这里的方法名与xml中的方法名对应。 public void click(View v) { TextView tv = (TextView) v; Toast.makeText(this, tv.getText(), Toast.LENGTH_SHORT).show(); } }
侧滑菜单:ViewGroup
1 package com.tai.dandelion.view; 2 3 import android.content.Context; 4 import android.util.AttributeSet; 5 import android.view.MotionEvent; 6 import android.view.View; 7 import android.view.ViewConfiguration; 8 import android.view.ViewGroup; 9 import android.widget.Scroller; 10 11 public class SlideMenu extends ViewGroup 12 { 13 private int touchSlop; 14 public SlideMenu(Context context, AttributeSet attrs) 15 { 16 super(context, attrs); 17 mScroller = new Scroller(context); 18 //startX, startY, dx, dy,duration 19 //滑动间距的距离 默认为8 20 touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); 21 } 22 23 //测量出所有子布局的宽和高 24 @Override 25 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) 26 { 27 super.onMeasure(widthMeasureSpec, heightMeasureSpec); 28 //这个super必须要重写的 29 measureView(widthMeasureSpec,heightMeasureSpec); 30 } 31 /** 32 * int widthMeasureSpec, int heightMeasureSpec 33 * @param widthMeasureSpec 父布局的测量 34 * @param heightMeasureSpec 35 */ 36 private void measureView(int widthMeasureSpec, int heightMeasureSpec) 37 { 38 //测量菜单布局 39 View menuView = getChildAt(0); 40 menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec); 41 //测量主界面的布局 42 View mainView = getChildAt(1); 43 mainView.measure(widthMeasureSpec, heightMeasureSpec); 44 45 } 46 //设置菜单和主界面的布局 47 @Override 48 protected void onLayout(boolean chenged, int l, int t, int r, int b) 49 { 50 //布置菜单的位置 51 View menuView = getChildAt(0); 52 //得到测量之后的边长 53 menuView.layout(-menuView.getMeasuredWidth(), 0, 0, b); 54 //布置主界面的位置 55 View mainView =getChildAt(1); 56 57 mainView.layout(0, 0, r, b); 58 59 } 60 private int mMostRecentX;//最后一次的X轴偏移量 61 private int MenuScreen = 0;//菜单页面 62 private int MainScreen = 1;//主界面 63 private int mCurrentScreen = MainScreen;//当前屏幕的主界面 64 //定义数据模拟器 来动态模拟数据的增量 65 private Scroller mScroller; 66 67 @Override 68 public boolean onTouchEvent(MotionEvent event) 69 { 70 switch (event.getAction()) 71 { 72 case MotionEvent.ACTION_DOWN: 73 mMostRecentX = (int) event.getX(); 74 break; 75 case MotionEvent.ACTION_MOVE: 76 //最新的X轴偏移量 77 int moveX = (int) event.getX(); 78 //增量值 79 int detaX = mMostRecentX - moveX; 80 //把最新的X轴偏移量赋值给最后一次的X轴偏移量 81 mMostRecentX = moveX; 82 83 //得到X轴移动后的偏移量 84 int newScrolLX = (int) (getScrollX() + detaX); 85 //当前X轴的偏移量超过了菜单的边界 86 if(newScrolLX<-getChildAt(0).getWidth()) 87 { 88 //回到菜单的左边界 89 scrollTo(-getChildAt(0).getWidth(), 0); 90 } 91 else if(newScrolLX>0) 92 { 93 //回到主界面的左边界 94 scrollTo(0, 0); 95 } 96 else 97 { 98 scrollBy(detaX, 0); 99 } 100 break; 101 case MotionEvent.ACTION_UP : 102 //最新的X轴偏移量 103 int scrollX = (int) getScrollX(); 104 //菜单的中心X轴 105 int menuXCenter = -getChildAt(0).getWidth()/2; 106 if(scrollX>menuXCenter) 107 {//切换到主界面 108 mCurrentScreen = MainScreen; 109 } 110 else 111 {//切换到菜单界面 112 mCurrentScreen = MenuScreen; 113 } 114 switchScreen(); 115 break; 116 default: 117 break; 118 } 119 120 return true; 121 } 122 123 private void switchScreen() 124 { 125 int scrollX = getScrollX(); 126 int dx = 0; 127 if(mCurrentScreen == MainScreen) 128 {//切换到主界面 129 // scrollTo(0, 0); 130 dx = 0-scrollX; 131 } 132 else if(mCurrentScreen == MenuScreen) 133 {//切换到菜单界面 134 // scrollTo(-getChildAt(0).getWidth(), 0); 135 dx = -getChildAt(0).getWidth()-scrollX; 136 } 137 mScroller.startScroll(scrollX, 0, dx, 0, Math.abs(dx)*3); 138 139 invalidate();//invalidate --> drawChild -->chlid.draw -->computerScroll 140 } 141 @Override 142 public void computeScroll() 143 { 144 //invaliadate调用此方法,更新X轴的偏移量 145 if(mScroller.computeScrollOffset()) //判断是否正在模拟数据中,true 正在进行 146 { 147 scrollTo(mScroller.getCurrX(), 0); 148 149 invalidate();//引起computeScroll的调用 150 } 151 } 152 //时候显示菜单 153 public boolean isShow() 154 { 155 return mCurrentScreen == MainScreen; 156 } 157 158 public void hideMenu() 159 { 160 mCurrentScreen = MainScreen; 161 switchScreen(); 162 } 163 164 public void showMenu() 165 { 166 mCurrentScreen = MenuScreen; 167 switchScreen(); 168 } 169 /** 170 * 拦截事件的方法 171 */ 172 @Override 173 public boolean onInterceptTouchEvent(MotionEvent ev) 174 { 175 switch (ev.getAction()) 176 { 177 case MotionEvent.ACTION_DOWN: 178 mMostRecentX = (int) ev.getX(); 179 break; 180 case MotionEvent.ACTION_MOVE: 181 int diffX = (int) (ev.getX() - mMostRecentX); 182 if(Math.abs(diffX)>touchSlop) 183 { 184 return true; 185 } 186 break; 187 default: 188 break; 189 } 190 return super.onInterceptTouchEvent(ev); 191 } 192 }
主要的核心方法:Scrollto、ScrollBy
invalidate();//invalidate --> drawChild -->chlid.draw -->computerScroll 这里比较复杂,大家可以查阅一下有关资料
布局文件:
1 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 2 xmlns:tools="http://schemas.android.com/tools" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 tools:context=".MainActivity" > 6 7 <com.tai.dandelion.view.SlideMenu 8 android:id="@+id/slidmenu" 9 android:layout_width="fill_parent" 10 android:layout_height="fill_parent"> 11 <include layout="@layout/slidemenu_menu"/> 12 <include layout="@layout/mian"/> 13 </com.tai.dandelion.view.SlideMenu> 14 15 16 </RelativeLayout>
非android原生控件定义的时候要写上自定义类的全名
com.tai.dandelion.view.SlideMenu
侧滑主界面
1 <?xml version="1.0" encoding="utf-8"?> 2 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="match_parent" 4 android:layout_height="match_parent" 5 android:orientation="vertical" > 6 <LinearLayout 7 android:layout_width="fill_parent" 8 android:layout_height="wrap_content" 9 android:orientation="horizontal" 10 android:background="@drawable/top_bar_bg"> 11 <ImageView 12 android:id="@+id/iv_slidmenu_back" 13 android:layout_width="wrap_content" 14 android:layout_height="wrap_content" 15 android:background="@drawable/main_back" 16 /> 17 <View android:layout_width="1dip" 18 android:layout_height="fill_parent" 19 android:background="@drawable/top_bar_divider" 20 android:layout_margin="5dip"/> 21 <TextView 22 android:layout_width="wrap_content" 23 android:layout_height="wrap_content" 24 android:layout_gravity="center_vertical" 25 android:layout_marginLeft="55dip" 26 android:text="title" 27 android:textSize="26sp" 28 android:textColor="@android:color/white"/> 29 </LinearLayout> 30 31 32 33 <TextView 34 android:layout_width="fill_parent" 35 android:layout_height="fill_parent" 36 android:text="内容" 37 android:gravity="center" 38 android:textColor="#ff0000" 39 android:textSize="26sp"/> 40 41 42 43 44 </LinearLayout>
侧滑隐藏菜单
1 <?xml version="1.0" encoding="utf-8"?> 2 <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 3 android:layout_width="240dip" 4 android:layout_height="match_parent" > 5 <!-- ScrollView只允许有一个子控件 --> 6 <LinearLayout 7 android:layout_width="240dip" 8 android:background="@drawable/menu_bg" 9 android:layout_height="wrap_content" 10 android:orientation="vertical" > 11 <TextView 12 style="@style/menu_style" 13 android:text="新闻" 14 android:drawableLeft="@drawable/tab_news" 15 /> 16 <TextView 17 style="@style/menu_style" 18 android:text="订阅" 19 android:drawableLeft="@drawable/tab_read" 20 /> 21 <TextView 22 style="@style/menu_style" 23 android:text="菜单" 24 android:drawableLeft="@drawable/tab_pics" 25 /> 26 <TextView 27 style="@style/menu_style" 28 android:text="本地" 29 android:drawableLeft="@drawable/tab_local" 30 /> 31 <TextView 32 style="@style/menu_style" 33 android:text="跟帖" 34 android:drawableLeft="@drawable/tab_ties" 35 /> 36 <TextView 37 style="@style/menu_style" 38 android:text="投票" 39 android:drawableLeft="@drawable/tab_vote" 40 /> 41 <TextView 42 style="@style/menu_style" 43 android:text="聚合阅读" 44 android:drawableLeft="@drawable/tab_focus" 45 /> 46 </LinearLayout> 47 48 49 </ScrollView>
style中的菜单的样式:
1 <style name="menu_style"> 2 <item name="android:layout_width">fill_parent</item> 3 <item name="android:layout_height">wrap_content</item> 4 <item name="android:paddingTop">10dip</item> 5 <item name="android:paddingBottom">10dip</item> 6 <item name="android:textColor">@android:color/white</item> 7 <item name="android:background">@drawable/text_bg</item> 8 <item name="android:textSize">23sp</item> 9 <item name="android:gravity">center_vertical</item> 10 <item name="android:paddingLeft">15dip</item> 11 <item name="android:drawablePadding">30dip</item> 12 <item name="android:clickable">true</item> 13 <item name="android:onClick">click</item> 14 </style>
菜单项的选择器
1 <?xml version="1.0" encoding="utf-8"?> 2 <selector xmlns:android="http://schemas.android.com/apk/res/android" > 3 <item android:state_pressed="true" android:drawable="@color/press"></item> 4 <item android:state_pressed="false" android:drawable="@color/pressed"></item> 5 </selector>
Manifast中Activity的声明就这里就不贴了。别的基本没什么。代码就在这里,有用的到的朋友可以研究一下。
整理By android小白。
最终效果: