Android侧拉菜单实现
2016-09-02 20:41
274 查看
本文采用自定义控件实现Android侧拉效果,首先建一个工程名字就叫做Sliding。
修改MainActivity
建一个SlideMenu
然后是几个布局,修改activity_main.xml
layout_left_menu.xml
layout_main_content.xml
在drawable下建一个选择器selector_menu_bt_bg.xml
再改下样式,color,具体看源代码
修改MainActivity
public class MainActivity extends Activity implements OnClickListener{ private SlideMenu sm; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.activity_main); sm = (SlideMenu) findViewById(R.id.sm); findViewById(R.id.ib_back).setOnClickListener(this); } public void onTabClick(View view){ } @Override public void onClick(View v) { sm.switchState(); } }
建一个SlideMenu
/** * 侧滑面板控件, 抽屉面板. * @author poplar * * 测量 摆放 绘制 measure -> layout -> draw | | | onMeasure -> onLayout -> onDraw 重写这些方法, 实现自定义控件 View流程 onMeasure() (在这个方法里指定自己的宽高) -> onDraw() (绘制自己的内容) ViewGroup流程 onMeasure() (指定自己的宽高, 所有子View的宽高)-> onLayout() (摆放所有子View) -> onDraw() (绘制内容) * */ public class SlideMenu extends ViewGroup { private float downX; // 按下的x坐标 private float downY; // 按下的y坐标 private float moveX; public static final int MAIN_STATE = 0; public static final int MENU_STATE = 1; private int currentState = MAIN_STATE; // 当前模式 private Scroller scroller; public SlideMenu(Context context) { super(context); init(); } public SlideMenu(Context context, AttributeSet attrs) { super(context, attrs); init(); } public SlideMenu(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(); } private void init() { // 初始化滚动器, 数值模拟器 scroller = new Scroller(getContext()); } /** * 测量并设置 所有子View的宽高 * widthMeasureSpec: 当前控件的宽度测量规则 * heightMeasureSpec: 当前控件的高度测量规则 */ @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { // 指定左面板的宽高 View leftMenu = getChildAt(0); leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec); // 指定主面板的宽高 View mainContent = getChildAt(1); mainContent.measure(widthMeasureSpec, heightMeasureSpec); super.onMeasure(widthMeasureSpec, heightMeasureSpec); } /** * changed: 当前控件的尺寸大小, 位置 是否发生了变化 * left:当前控件 左边距 * top:当前控件 顶边距 * right:当前控件 右边界 * bottom:当前控件 下边界 */ @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { // 摆放内容, 左面板 View leftMenu = getChildAt(0); leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b); // 主面板 getChildAt(1).layout(l, t, r, b); } /** * 处理触摸事件 */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: downX = event.getX(); break; case MotionEvent.ACTION_MOVE: moveX = event.getX(); // 将要发生的偏移量/变化量 int scrollX = (int) (downX - moveX); // 计算将要滚动到的位置, 判断是否会超出去, 超出去了.不执行scrollBy // getScrollX() 当前滚动到的位置 int newScrollPosition = getScrollX() + scrollX; if (newScrollPosition < -getChildAt(0).getMeasuredWidth()){ // 限定左边界 // < -240 scrollTo(-getChildAt(0).getMeasuredWidth(), 0); } else if (newScrollPosition > 0){ // 限定右边界 // > 0 scrollTo(0, 0); } else { // 让变化量生效 scrollBy(scrollX, 0); } downX = moveX; break; case MotionEvent.ACTION_UP: // 根据当前滚动到的位置, 和左面板的一半进行比较 int leftCenter = (int) (- getChildAt(0).getMeasuredWidth() / 2.0f); if(getScrollX() < leftCenter){ // 打开, 切换成菜单面板 currentState = MENU_STATE; updateCurrentContent(); }else { // 关闭, 切换成主面板 currentState = MAIN_STATE; updateCurrentContent(); } break; default: break; } return true; // 消费事件 } /** * 根据当前的状态, 执行 关闭/开启 的动画 */ private void updateCurrentContent() { int startX = getScrollX(); int dx = 0; // 平滑滚动 if(currentState == MENU_STATE){ // 打开菜单 // scrollTo(-getChildAt(0).getMeasuredWidth(), 0); // dx = 结束位置(-240) - 开始位置(-200) = -40 // dx = 0 - (-10) = 10 dx = -getChildAt(0).getMeasuredWidth() - startX; } else { // 恢复主界面 // scrollTo(0, 0); dx = 0 - startX; } // startX: 开始的x值 // startY: 开始的y值 // dx: 将要发生的水平变化量. 移动的x距离 // dy: 将要发生的竖直变化量. 移动的y距离 // duration : 数据模拟持续的时长 // 1. 开始平滑的数据模拟 int duration = Math.abs(dx * 2); // 0 -> 1200 scroller.startScroll(startX, 0, dx, 0, duration); // - 200 -> -240 // - 201 -> -202 -> -203 .... -236 -> -240 invalidate();// 重绘界面 -> drawChild() -> computeScroll(); } //2. 维持动画的继续 @Override public void computeScroll() { super.computeScroll(); if(scroller.computeScrollOffset()){ // 直到duration事件以后, 结束 // true, 动画还没有结束 // 获取当前模拟的数据, 也就是要滚动到的位置 int currX = scroller.getCurrX(); System.out.println("currX: " + currX); scrollTo(currX, 0); // 滚过去 invalidate(); // 重绘界面-> drawChild() -> computeScroll();循环 } } public void open(){ currentState = MENU_STATE; updateCurrentContent(); } public void close(){ currentState = MAIN_STATE; updateCurrentContent(); } public void switchState(){ if(currentState == MAIN_STATE){ open(); }else { close(); } } public int getCurrentState(){ return currentState; } /** * 拦截判断 */ @Override public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: downX = ev.getX(); downY = ev.getY(); break; case MotionEvent.ACTION_MOVE: float xOffset = Math.abs(ev.getX() - downX); float yOffset = Math.abs(ev.getY() - downY); if(xOffset > yOffset && xOffset > 5){ // 水平方向超出一定距离时,才拦截 return true; // 拦截此次触摸事件, 界面的滚动 } break; case MotionEvent.ACTION_UP: break; default: break; } return super.onInterceptTouchEvent(ev); } }
然后是几个布局,修改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=".MainActivity" > <com.mengxin.sliding.ui.SlideMenu android:id="@+id/sm" android:layout_width="match_parent" android:layout_height="match_parent" > <include layout="@layout/layout_left_menu"/> <include layout="@layout/layout_main_content"/>" </com.mengxin.sliding.ui.SlideMenu> </RelativeLayout>
layout_left_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" > <LinearLayout android:layout_width="240dp" android:layout_height="match_parent" android:background="@drawable/menu_bg" android:orientation="vertical" > <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_news" android:text="新闻" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_read" android:text="订阅" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_local" android:text="本地" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_ties" android:text="跟帖" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_pics" android:text="图片" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_ugc" android:text="话题" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_vote" android:text="投票" /> <TextView style="@style/style_bt_text" android:drawableLeft="@drawable/tab_focus" android:text="聚合阅读" /> </LinearLayout> </ScrollView>
layout_main_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:background="#FFF" android:orientation="vertical" > <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@drawable/top_bar_bg" android:orientation="horizontal" > <ImageButton android:id="@+id/ib_back" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@null" android:src="@drawable/main_back" /> <View android:layout_width="1dp" android:layout_height="match_parent" android:background="@drawable/top_bar_divider" /> <TextView android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_gravity="center_vertical" android:layout_marginLeft="10dp" android:text="黑马新闻" android:textColor="#FFF" android:textSize="24sp" /> </LinearLayout> <TextView android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="钓鱼岛是中国的! 苍老师才是世界的." android:textSize="26dp" /> </LinearLayout>
在drawable下建一个选择器selector_menu_bt_bg.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_pressed="true" android:drawable="@color/bt_bg_pressed"></item> <item android:drawable="@android:color/transparent"/> </selector>
再改下样式,color,具体看源代码
相关文章推荐
- Android实现自定义菜单
- Android提高十七篇之多级树形菜单的实现
- Android之用PopupWindow实现弹出菜单
- Android实现矩形设置菜单
- Android 多级菜单实现
- android简单demo学习系例之菜单实现
- Android onItemLongClick+onCreateContextMenu实现长按ListItem弹出不同菜单
- Android如何实现uc浏览器一样的菜单
- 【iPhone Demo】地图自定义大头针如何利用Android TabHost+ActivityGroup+Broadcast实现类似于iPhone的底部菜单
- Android菜单功能的实现
- Android提高十七篇之多级树形菜单的实现
- Android之用PopupWindow实现弹出菜单
- android菜单的实现
- Android - 底部菜单架构设计及封装实现
- Android提高十七篇之多级树形菜单的实现
- android 实现按钮键菜单的方法
- Android:实现一种浮动选择菜单的效果
- android中菜单的实现(初级)
- Android 实现uc浏览器一样的菜单
- Android实现新浪微博中的分组菜单对话框