`

Android学习之左侧滑动菜单

阅读更多

MainActivity.java:

package com.example.slidinglayout;

import android.app.Activity;
import android.os.Bundle;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.ListView;
import android.widget.TextView;
import android.widget.Toast;

public class MainActivity extends Activity {

	/**
	 * 侧滑布局对象,用于通过手指滑动将左侧的菜单布局进行显示或隐藏。
	 */
	private SlidingLayout slidingLayout;

	/**
	 * menu按钮,点击按钮展示左侧布局,再点击一次隐藏左侧布局。
	 */
	private Button menuButton;
	
	//测试TextView
	private TextView mytv;

	/**
	 * 放在content布局中的ListView。
	 */
	private ListView contentListView;

	/**
	 * 作用于contentListView的适配器。
	 */
	private ArrayAdapter<String> contentListAdapter;

	/**
	 * 用于填充contentListAdapter的数据源。
	 */
	private String[] contentItems = { "Content Item 1", "Content Item 2", "Content Item 3",
			"Content Item 4", "Content Item 5", "Content Item 6", "Content Item 7",
			"Content Item 8", "Content Item 9", "Content Item 10", "Content Item 11",
			"Content Item 12", "Content Item 13", "Content Item 14", "Content Item 15",
			"Content Item 16" };

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		setContentView(R.layout.activity_main);
		slidingLayout = (SlidingLayout) findViewById(R.id.slidingLayout);
		menuButton = (Button) findViewById(R.id.menuButton);
		mytv = (TextView) findViewById(R.id.mytv);
		contentListView = (ListView) findViewById(R.id.contentList);
		contentListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
				contentItems);
		contentListView.setAdapter(contentListAdapter);
		// 将监听滑动事件绑定在contentListView上
		slidingLayout.setScrollEvent(contentListView);
		menuButton.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				if (slidingLayout.isLeftLayoutVisible()) {
					slidingLayout.scrollToRightLayout();
				} else {
					if (slidingLayout.getLeftLayout().getVisibility() != View.VISIBLE) {
						slidingLayout.getLeftLayout().setVisibility(View.VISIBLE);
					}
					slidingLayout.scrollToLeftLayout();
				}
			}

		});
		mytv.setOnClickListener(new OnClickListener() {
			@Override
			public void onClick(View v) {
				Toast.makeText(MainActivity.this, "点击TextView",Toast.LENGTH_SHORT).show();  
			}

		});
		contentListView.setOnItemClickListener(new OnItemClickListener() {
			@Override
			public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
				String text = contentItems[position];
				Toast.makeText(MainActivity.this, text, Toast.LENGTH_SHORT).show();
			}
		});
	}

}
 

 

activity_main.xml:

 

<com.example.slidinglayout.SlidingLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/slidingLayout"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <RelativeLayout
        android:id="@+id/menu"
        android:layout_width="270dip"
        android:layout_height="fill_parent"
        android:layout_alignParentLeft="true"
        android:background="#00ccff"
        android:visibility="invisible" >

        <TextView
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_centerInParent="true"
            android:text="This is menu"
            android:textColor="#000000"
            android:textSize="28sp" />
    </RelativeLayout>

    <LinearLayout
        android:id="@+id/content"
        android:layout_width="320dip"
        android:layout_height="fill_parent"
        android:layout_alignParentRight="true"
        android:background="#e9e9e9"
        android:orientation="vertical"
        android:visibility="visible" >

        <Button
            android:id="@+id/menuButton"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="Menu" />
        
        <TextView   
            android:id="@+id/mytv"  
            android:textSize="18sp"  
            android:layout_width="wrap_content" 
            android:textColor="#000000"
            android:text="我的测试" 
            android:layout_marginLeft="10dp"
            android:layout_height="wrap_content" />  

        <ListView
            android:id="@+id/contentList"
            android:layout_width="fill_parent"
            android:layout_height="fill_parent"
            android:cacheColorHint="#00000000" >
        </ListView>
    </LinearLayout>

</com.example.slidinglayout.SlidingLayout>

 

 SlidingLayout.java:

 

package com.example.slidinglayout;

import android.content.Context;
import android.os.AsyncTask;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.RelativeLayout;

public class SlidingLayout extends RelativeLayout implements OnTouchListener {

	/**
	 * 滚动显示和隐藏左侧布局时,手指滑动需要达到的速度。
	 */
	public static final int SNAP_VELOCITY = 200;

	/**
	 * 屏幕宽度值。
	 */
	private int screenWidth;

	/**
	 * 右侧布局最多可以滑动到的左边缘。
	 */
	private int leftEdge = 0;

	/**
	 * 右侧布局最多可以滑动到的右边缘。
	 */
	private int rightEdge = 0;

	/**
	 * 在被判定为滚动之前用户手指可以移动的最大值。
	 */
	private int touchSlop;

	/**
	 * 记录手指按下时的横坐标。
	 */
	private float xDown;

	/**
	 * 记录手指按下时的纵坐标。
	 */
	private float yDown;

	/**
	 * 记录手指移动时的横坐标。
	 */
	private float xMove;

	/**
	 * 记录手指移动时的纵坐标。
	 */
	private float yMove;

	/**
	 * 记录手机抬起时的横坐标。
	 */
	private float xUp;

	/**
	 * 左侧布局当前是显示还是隐藏。只有完全显示或隐藏时才会更改此值,滑动过程中此值无效。
	 */
	private boolean isLeftLayoutVisible;

	/**
	 * 是否正在滑动。
	 */
	private boolean isSliding;

	/**
	 * 左侧布局对象。
	 */
	private View leftLayout;

	/**
	 * 右侧布局对象。
	 */
	private View rightLayout;

	/**
	 * 用于监听侧滑事件的View。
	 */
	private View mBindView;

	/**
	 * 左侧布局的参数,通过此参数来重新确定左侧布局的宽度,以及更改leftMargin的值。
	 */
	private MarginLayoutParams leftLayoutParams;

	/**
	 * 右侧布局的参数,通过此参数来重新确定右侧布局的宽度。
	 */
	private MarginLayoutParams rightLayoutParams;

	/**
	 * 用于计算手指滑动的速度。
	 */
	private VelocityTracker mVelocityTracker;

	/**
	 * 重写SlidingLayout的构造函数,其中获取了屏幕的宽度。
	 * 
	 * @param context
	 * @param attrs
	 */
	public SlidingLayout(Context context, AttributeSet attrs) {
		super(context, attrs);
		WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
		screenWidth = wm.getDefaultDisplay().getWidth();
		touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
	}

	public View getLeftLayout() {
		return leftLayout;
	}


	/**
	 * 绑定监听侧滑事件的View,即在绑定的View进行滑动才可以显示和隐藏左侧布局。
	 * 
	 * @param bindView
	 *            需要绑定的View对象。
	 */
	public void setScrollEvent(View bindView) {
		mBindView = bindView;
		mBindView.setOnTouchListener(this);
	}

	/**
	 * 将屏幕滚动到左侧布局界面,滚动速度设定为-30.
	 */
	public void scrollToLeftLayout() {
		new ScrollTask().execute(-30);
	}

	/**
	 * 将屏幕滚动到右侧布局界面,滚动速度设定为30.
	 */
	public void scrollToRightLayout() {
		new ScrollTask().execute(30);
	}

	/**
	 * 左侧布局是否完全显示出来,或完全隐藏,滑动过程中此值无效。
	 * 
	 * @return 左侧布局完全显示返回true,完全隐藏返回false。
	 */
	public boolean isLeftLayoutVisible() {
		return isLeftLayoutVisible;
	}

	/**
	 * 在onLayout中重新设定左侧布局和右侧布局的参数。
	 */
	@Override
	protected void onLayout(boolean changed, int l, int t, int r, int b) {
		super.onLayout(changed, l, t, r, b);
		if (changed) {
			// 获取左侧布局对象
			leftLayout = getChildAt(0);
			leftLayoutParams = (MarginLayoutParams) leftLayout
					.getLayoutParams();
			leftLayoutParams.width = (int) (screenWidth * 0.8); // 设置左侧为屏幕宽度的0.8倍
			rightEdge = -leftLayoutParams.width;
			// 获取右侧布局对象
			rightLayout = getChildAt(1);
			rightLayoutParams = (MarginLayoutParams) rightLayout
					.getLayoutParams();
			rightLayoutParams.width = screenWidth;
			rightLayout.setLayoutParams(rightLayoutParams);
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		createVelocityTracker(event);
		if (leftLayout.getVisibility() != View.VISIBLE) {
			leftLayout.setVisibility(View.VISIBLE);
		}
		switch (event.getAction()) {
		case MotionEvent.ACTION_DOWN:
			// 手指按下时,记录按下时的横坐标
			xDown = event.getRawX();
			yDown = event.getRawY();
			break;
		case MotionEvent.ACTION_MOVE:
			// 手指移动时,对比按下时的横坐标,计算出移动的距离,来调整右侧布局的leftMargin值,从而显示和隐藏左侧布局
			xMove = event.getRawX();
			yMove = event.getRawY();
			int moveDistanceX = (int) (xMove - xDown);
			int distanceY = (int) (yMove - yDown);
			if (!isLeftLayoutVisible && moveDistanceX >= touchSlop
					&& (isSliding || Math.abs(distanceY) <= touchSlop)) {
				isSliding = true;
				rightLayoutParams.rightMargin = -moveDistanceX;
				if (rightLayoutParams.rightMargin < rightEdge) {
					rightLayoutParams.rightMargin = rightEdge;
				}
				rightLayout.setLayoutParams(rightLayoutParams);
			}
			if (isLeftLayoutVisible && -moveDistanceX >= touchSlop) {
				isSliding = true;
				rightLayoutParams.rightMargin = rightEdge - moveDistanceX;
				if (rightLayoutParams.rightMargin > leftEdge) {
					rightLayoutParams.rightMargin = leftEdge;
				}
				rightLayout.setLayoutParams(rightLayoutParams);
			}
			break;
		case MotionEvent.ACTION_UP:
			xUp = event.getRawX();
			int upDistanceX = (int) (xUp - xDown);
			if (isSliding) {
				// 手指抬起时,进行判断当前手势的意图,从而决定是滚动到左侧布局,还是滚动到右侧布局
				if (wantToShowLeftLayout()) {
					if (shouldScrollToLeftLayout()) {
						scrollToLeftLayout();
					} else {
						scrollToRightLayout();
					}
				} else if (wantToShowRightLayout()) {
					if (shouldScrollToRightLayout()) {
						scrollToRightLayout();
					} else {
						scrollToLeftLayout();
					}
				}
			} else if (upDistanceX < touchSlop && isLeftLayoutVisible) {
				scrollToRightLayout();
			}
			recycleVelocityTracker();
			break;
		}
		if (v.isEnabled()) {
			if (isSliding) {
				unFocusBindView();
				return true;
			}
			if (isLeftLayoutVisible) {
				return true;
			}
			return false;
		}
		return true;
	}

	/**
	 * 判断当前手势的意图是不是想显示右侧布局。如果手指移动的距离是负数,且当前左侧布局是可见的,则认为当前手势是想要显示右侧布局。
	 * 
	 * @return 当前手势想显示右侧布局返回true,否则返回false。
	 */
	private boolean wantToShowRightLayout() {
		return xUp - xDown < 0 && isLeftLayoutVisible;
	}

	/**
	 * 判断当前手势的意图是不是想显示左侧布局。如果手指移动的距离是正数,且当前左侧布局是不可见的,则认为当前手势是想要显示左侧布局。
	 * 
	 * @return 当前手势想显示左侧布局返回true,否则返回false。
	 */
	private boolean wantToShowLeftLayout() {
		return xUp - xDown > 0 && !isLeftLayoutVisible;
	}

	/**
	 * 判断是否应该滚动将左侧布局展示出来。如果手指移动距离大于屏幕的1/2,或者手指移动速度大于SNAP_VELOCITY,
	 * 就认为应该滚动将左侧布局展示出来。
	 * 
	 * @return 如果应该滚动将左侧布局展示出来返回true,否则返回false。
	 */
	private boolean shouldScrollToLeftLayout() {
		return xUp - xDown > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
	}

	/**
	 * 判断是否应该滚动将右侧布局展示出来。如果手指移动距离加上leftLayoutPadding大于屏幕的1/2,
	 * 或者手指移动速度大于SNAP_VELOCITY, 就认为应该滚动将右侧布局展示出来。
	 * 
	 * @return 如果应该滚动将右侧布局展示出来返回true,否则返回false。
	 */
	private boolean shouldScrollToRightLayout() {
		return xDown - xUp > leftLayoutParams.width / 2 || getScrollVelocity() > SNAP_VELOCITY;
	}

	/**
	 * 创建VelocityTracker对象,并将触摸事件加入到VelocityTracker当中。
	 * 
	 * @param event
	 *            右侧布局监听控件的滑动事件
	 */
	private void createVelocityTracker(MotionEvent event) {
		if (mVelocityTracker == null) {
			mVelocityTracker = VelocityTracker.obtain();
		}
		mVelocityTracker.addMovement(event);
	}

	/**
	 * 获取手指在右侧布局的监听View上的滑动速度。
	 * 
	 * @return 滑动速度,以每秒钟移动了多少像素值为单位。
	 */
	private int getScrollVelocity() {
		mVelocityTracker.computeCurrentVelocity(1000);
		int velocity = (int) mVelocityTracker.getXVelocity();
		return Math.abs(velocity);
	}

	/**
	 * 回收VelocityTracker对象。
	 */
	private void recycleVelocityTracker() {
		mVelocityTracker.recycle();
		mVelocityTracker = null;
	}

	/**
	 * 使用可以获得焦点的控件在滑动的时候失去焦点。
	 */
	private void unFocusBindView() {
		if (mBindView != null) {
			mBindView.setPressed(false);
			mBindView.setFocusable(false);
			mBindView.setFocusableInTouchMode(false);
		}
	}

	class ScrollTask extends AsyncTask<Integer, Integer, Integer> {

		@Override
		protected Integer doInBackground(Integer... speed) {
			int rightMargin = rightLayoutParams.rightMargin;
			// 根据传入的速度来滚动界面,当滚动到达左边界或右边界时,跳出循环。
			while (true) {
				rightMargin = rightMargin + speed[0];
				if (rightMargin < rightEdge) {
					rightMargin = rightEdge;
					break;
				}
				if (rightMargin > leftEdge) {
					rightMargin = leftEdge;
					break;
				}
				publishProgress(rightMargin);
				// 为了要有滚动效果产生,每次循环使线程睡眠20毫秒,这样肉眼才能够看到滚动动画。
				sleep(15);
			}
			if (speed[0] > 0) {
				isLeftLayoutVisible = false;
			} else {
				isLeftLayoutVisible = true;
			}
			isSliding = false;
			return rightMargin;
		}

		@Override
		protected void onProgressUpdate(Integer... rightMargin) {
			rightLayoutParams.rightMargin = rightMargin[0];
			rightLayout.setLayoutParams(rightLayoutParams);
			unFocusBindView();
		}

		@Override
		protected void onPostExecute(Integer rightMargin) {
			rightLayoutParams.rightMargin = rightMargin;
			rightLayout.setLayoutParams(rightLayoutParams);
		}
	}

	/**
	 * 使当前线程睡眠指定的毫秒数。
	 * 
	 * @param millis
	 *            指定当前线程睡眠多久,以毫秒为单位
	 */
	private void sleep(long millis) {
		try {
			Thread.sleep(millis);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
}

 

 

 

参考:http://blog.csdn.net/guolin_blog/article/details/8744400

  • 大小: 17.8 KB
  • 大小: 16 KB
分享到:
评论

相关推荐

    Android左右滑动菜单

    在Android应用开发中,滑动菜单(Sliding Menu)是一种常见的设计模式,它允许用户通过在屏幕边缘滑动来展示或隐藏一个侧边栏菜单。这种设计为用户提供了一种直观的方式来访问更多的功能或选项,而不会占据屏幕的...

    android左侧或右侧可选滑动菜单

    以上就是实现Android左侧或右侧滑动菜单所需的关键知识点。通过理解并应用这些概念,开发者可以创建出符合现代移动应用设计标准的交互式菜单。在实际项目中,还可以根据需求进行个性化定制,比如添加过渡动画、...

    Android双向滑动菜单带按钮版

    本文将详细解析"Android双向滑动菜单带按钮版"这一主题,结合标签"Android", "双向滑动", "滑动菜单", "slidemenu"和"特效",以及压缩包中的"BidirSlidingLayout"文件,我们将深入讨论如何实现一个具有双向滑动功能...

    android sliding menu 滑动菜单

    在Android应用开发中,滑动菜单(Sliding Menu)是一种常见的设计模式,它允许用户通过从屏幕边缘向内滑动来展示隐藏的侧边栏菜单。这种设计在移动设备上非常流行,因为它提供了便捷的导航方式,特别是在内容丰富的...

    DrawerLayout左侧滑动菜单

    在这个场景中,我们关注的是左侧的滑动菜单,它为用户提供了一个可隐藏但易于访问的附加操作区域。让我们深入探讨如何利用Toolbar和PopupMenu来实现这个功能。 首先,DrawerLayout是Android Support Library中的一...

    Android左右菜单滑动

    2. **滑动菜单库**:Android社区提供了许多现成的库来简化滑动菜单的实现,例如`SlidingPaneLayout`、`DrawerLayout`等。这些库提供了一种简便的方式来创建滑动面板,允许内容视图随着用户的滑动而隐藏或显示。 3. ...

    Android滑动菜单 sidemenu

    Android滑动菜单,通常被称为侧滑菜单或者Sidemenu,是移动应用设计中常见的交互元素,尤其在Android平台上广泛使用。这种菜单允许用户通过在屏幕边缘(通常是左侧)进行滑动手势来显示或隐藏附加的功能选项,从而...

    android滑动菜单

    在Android应用开发中,滑动菜单(通常称为侧滑菜单或抽屉式导航)是一种常见的设计模式,用于提供隐藏...通过以上知识点的学习和实践,开发者可以创建出符合用户习惯且功能强大的滑动菜单,提升Android应用的用户体验。

    超炫android滑动菜单源码

    本资源提供的"超炫android滑动菜单源码"是一个专为Android平台设计的高效、美观的滑动菜单实现,其独特之处在于其视觉效果和交互体验。 首先,我们来深入了解滑动菜单的设计理念。滑动菜单通常隐藏在主界面的左侧或...

    Android滑动菜单框架完全解析,教你如何一分钟实现滑动菜单特效demo

    通过学习和理解这一过程,开发者不仅可以创建出个性化的滑动菜单,还能加深对Android视图系统和手势处理的理解。如果你遵循上述步骤并参考提供的链接资源,你将在短时间内实现一个功能完善的滑动菜单demo。

    android Drawlayout 左右侧滑动菜单

    下面将详细讨论`Drawlayout`的实现原理、相关组件以及如何在项目中实现左右侧滑动菜单。 首先,`SlidingDrawer`是Android SDK中提供的一个原生组件,但在API 21(Android 5.0 Lollipop)之后已被废弃。尽管如此,它...

    android模拟ios的滑动菜单

    总之,实现一个类似iOS的滑动菜单在Android中涉及到自定义ViewGroup、手势检测、视图动画等多个方面。通过`LeftSliderLayout`,我们可以为用户提供一个熟悉且流畅的交互体验,提升应用的整体质量。在实践中,不断...

    Android滑动菜单源码

    在Android应用开发中,滑动菜单(Sliding Menu)是一种常见的设计模式,它允许用户通过从屏幕边缘向内滑动来展示隐藏的侧边栏菜单。这种设计在移动设备上非常流行,因为它提供了便捷的导航方式,同时节省了屏幕空间...

    android 左右滑动菜单

    在Android开发中,实现左右滑动菜单是一种常见的交互设计,它可以提供类似iOS设备上"智慧无锡"的功能。这种设计能够使用户通过简单的手势操作在主界面与侧边菜单之间切换,提升应用程序的用户体验。以下是对如何在...

    android滑动菜单源码

    在Android应用开发中,滑动菜单(通常称为侧滑菜单或抽屉式菜单)是一种常见的设计模式,它允许用户通过从屏幕边缘滑动来显示或隐藏一个包含导航选项的菜单。这种设计通常用于大型应用程序,以提供一种简洁的方式来...

    android的DrawerLayout左右滑动菜单

    首先,DrawerLayout是Android Support Library中的一个ViewGroup,它允许开发者在主内容视图的左侧或右侧添加“抽屉”(Drawer),这些抽屉通常包含导航菜单或者设置选项。通过简单的触摸手势或硬件菜单键,用户可以...

    android_UI设计之左侧菜单滑动弹出(仿facebook)

    在Android应用开发中,UI设计是非常重要的一环,特别是对于用户体验有着直接影响的组件,比如滑动弹出的左侧菜单。这种设计常见于许多社交应用,如Facebook和人人网,因此在开发过程中,开发者们常常需要实现这样的...

    仿qq滑动菜单

    在Android应用开发中,"仿QQ滑动菜单"是一种常见的设计模式,用于实现类似QQ应用那样的侧滑导航功能。这种菜单通常隐藏在屏幕边缘,用户可以通过手势或按钮触发,显示一列可选的操作或者功能。它提升了用户体验,...

    Android实现3D推拉门式滑动菜单源码解析

    本文将深入解析如何在Android平台上实现这种3D效果的滑动菜单,以及如何优化源码以适应实际项目需求。 首先,3D推拉门式滑动菜单的核心在于通过Matrix和Camera类来实现视图的3D旋转效果。Matrix是Android图形库中...

Global site tag (gtag.js) - Google Analytics