赞
踩
前面已经讲过通过三方开源库SlideMenu来实现这种效果,请参考Android实现网易新闻客户端侧滑菜单(一)
今天通过自定义View来实现这种功能。
代码如下:
SlideMenu.java
- package com.jackie.slidemenu.view;
-
- import android.content.Context;
- import android.graphics.Canvas;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- import android.view.ViewConfiguration;
- import android.view.ViewGroup;
- import android.widget.Scroller;
-
- public class SlideMenu extends ViewGroup {
-
- private int mMostRecentX; // 最后一次x轴的偏移量
-
- private final int MENU_SCREEN = 0; // 菜单界面
- private final int MAIN_SCREEN = 1; // 主界面
- private int mCurrentScreen = MAIN_SCREEN; // 当前屏幕显示的是主界面
- private Scroller mScroller;
-
- private int touchSlop;
-
- public SlideMenu(Context context, AttributeSet attrs) {
- super(context, attrs);
- mScroller = new Scroller(context);
-
- touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
- }
-
- /**
- * 测量出所有子布局的宽和高
- */
- @Override
- protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(widthMeasureSpec, heightMeasureSpec);
-
- measureView(widthMeasureSpec, heightMeasureSpec);
- }
-
- /**
- * 测量所有子布局的宽和高
- * @param widthMeasureSpec 父布局也就是ViewGroup的宽度测量规格
- * @param heightMeasureSpec 父布局也就是ViewGroup的高度测量规格
- */
- private void measureView(int widthMeasureSpec, int heightMeasureSpec) {
- // 测量菜单的宽和高
- View menuView = getChildAt(0);
- menuView.measure(menuView.getLayoutParams().width, heightMeasureSpec);
-
- // 测量主界面的宽和高
- View mainView = getChildAt(1);
- mainView.measure(widthMeasureSpec, heightMeasureSpec); // 主界面的宽和高和父控件viewgroup的宽高一样
- }
-
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- // 布置菜单的位置
- View menuView = getChildAt(0);
- menuView.layout(-menuView.getMeasuredWidth(), 0, 0, b);
-
- // 布置主界面的位置
- View mainView = getChildAt(1);
- mainView.layout(0, 0, r, b);
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mMostRecentX = (int) event.getX();
- break;
- case MotionEvent.ACTION_MOVE:
- // 最新的x轴偏移量
- int moveX = (int) event.getX();
-
- // 增量值
- int deltaX = mMostRecentX - moveX;
-
- // 把最新的x轴偏移量赋值给成员变量
- mMostRecentX = moveX;
-
- // 得到x轴移动后的偏移量
- int newScrollX = getScrollX() + deltaX;
-
- if(newScrollX < -getChildAt(0).getWidth()) { // 当前屏幕x轴的偏移量超过了菜单的左边界
- // 回到菜单的左边界位置
- scrollTo(-getChildAt(0).getWidth(), 0);
- } else if(newScrollX > 0) { // 超过了主界面的右边界
- // 回到主界面的右边界
- scrollTo(0, 0);
- } else {
- scrollBy(deltaX, 0);
- }
- break;
- case MotionEvent.ACTION_UP:
- int scrollX = getScrollX(); // x轴最新的偏移量
-
- int menuXCenter = -getChildAt(0).getWidth() / 2; // 菜单x轴的中心点
-
- if(scrollX > menuXCenter) { // 切换到主界面
- mCurrentScreen = MAIN_SCREEN;
- } else { // 切换到菜单界面
- mCurrentScreen = MENU_SCREEN;
- }
- switchScreen();
- break;
- default:
- break;
- }
- return true;
- }
-
- /**
- * 根据mCurrentScreen切换屏幕
- */
- private void switchScreen() {
- int scrollX = getScrollX(); // 当前x轴的偏移量
- int dx = 0;
-
- if(mCurrentScreen == MAIN_SCREEN) { // 切换到主界面
- // scrollTo(0, 0);
- dx = 0 - scrollX;
- } else if(mCurrentScreen == MENU_SCREEN) { // 切换到菜单界面
- // scrollTo(-getChildAt(0).getWidth(), 0);
- dx = -getChildAt(0).getWidth() - scrollX;
- }
-
- mScroller.startScroll(scrollX, 0, dx, 0, Math.abs(dx) * 5);
-
- invalidate(); // invalidate -> drawChild -> child.draw -> computeScroll
- }
-
- /**
- * invalidate出发此方法, 更新屏幕的x轴的偏移量
- */
- @Override
- public void computeScroll() {
- if(mScroller.computeScrollOffset()) { // 判断是否正在模拟数据中, true 正在进行 false 数据模拟完毕
- scrollTo(mScroller.getCurrX(), 0);
-
- invalidate(); // 引起computeScroll的调用
- }
- }
-
- /**
- * 是否显示菜单
- * @return
- */
- public boolean isShowMenu() {
- return mCurrentScreen == MENU_SCREEN;
- }
-
- /**
- * 隐藏菜单
- */
- public void hideMenu() {
- mCurrentScreen = MAIN_SCREEN;
- switchScreen();
- }
-
- /**
- * 显示菜单
- */
- public void showMenu() {
- mCurrentScreen = MENU_SCREEN;
- switchScreen();
- }
-
- /**
- * 拦截事件的方法
- */
- @Override
- public boolean onInterceptTouchEvent(MotionEvent ev) {
- switch (ev.getAction()) {
- case MotionEvent.ACTION_DOWN:
- mMostRecentX = (int) ev.getX();
- break;
- case MotionEvent.ACTION_MOVE:
-
- int diffX = (int) (ev.getX() - mMostRecentX);
- if(Math.abs(diffX) > touchSlop) {
- return true;
- }
- break;
- default:
- break;
- }
- return super.onInterceptTouchEvent(ev);
- }
-
- }

MainActivity.java
- package com.jackie.slidemenu;
-
- import com.jackie.slidemenu.view.SlideMenu;
-
- import android.os.Bundle;
- import android.app.Activity;
- import android.view.Menu;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.view.Window;
- import android.widget.TextView;
- import android.widget.Toast;
-
- public class MainActivity extends Activity implements OnClickListener {
-
- private SlideMenu mSlideMenu;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 去除标题, 需要在setContentView之前调用
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- setContentView(R.layout.activity_main);
-
-
- mSlideMenu = (SlideMenu) findViewById(R.id.slidemenu);
- findViewById(R.id.iv_slidemenu_main_back).setOnClickListener(this);
-
-
- }
-
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- // Inflate the menu; this adds items to the action bar if it is present.
- getMenuInflater().inflate(R.menu.main, menu);
- return true;
- }
-
- @Override
- public void onClick(View v) {
- if(mSlideMenu.isShowMenu()) {
- mSlideMenu.hideMenu();
- } else {
- mSlideMenu.showMenu();
- }
- }
-
- public void click(View v) {
- TextView tv = (TextView) v;
- Toast.makeText(this, tv.getText(), 0).show();
- }
- }

Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。