activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal"
tools:context=".MainActivity" >
<LinearLayout
android:id="@+id/menu"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical"
android:background="#dddddddd"
>
<ListView
android:id="@+id/list_menu"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:cacheColorHint="#00000000"
android:orientation="vertical" >
</ListView>
</LinearLayout>
<LinearLayout
android:id="@+id/content"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#ffff0000"
android:orientation="vertical" >
<ListView
android:id="@+id/list_content"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:cacheColorHint="#00000000"
android:orientation="vertical" >
</ListView>
</LinearLayout>
</LinearLayout>
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/text1"
android:layout_width="fill_parent"
android:layout_height="30dp"
android:textColor="#ff00ff00"
/>
<TextView
android:id="@+id/text2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:textColor="#ffffffff"
android:visibility="gone"
/>
</LinearLayout>
MainActivity.java:
package com.example.renrenslidemenudemo;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import android.app.Activity;
import android.content.Context;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
import android.view.View;
import android.view.View.OnTouchListener;
import android.view.WindowManager;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.SimpleAdapter;
import android.widget.TextView;
public class MainActivity extends Activity implements OnTouchListener {
/**
* 滾動顯示和隱藏menu時,手指滑動需要達到的速度。
*/
public static final int SNAP_VELOCITY = 200;
/**
* 屏幕寬度值。
*/
private int screenWidth;
/**
* menu最多可以滑動到的左邊緣。值由menu佈局的寬度來定,marginLeft到達此值之後,不能再減少。
*/
private int leftEdge;
/**
* menu最多可以滑動到的右邊緣。值恆爲0,即marginLeft到達0之後,不能增加。
*/
private int rightEdge = 0;
/**
* menu完全顯示時,留給content的寬度值。
*/
private int menuPadding = 80;
/**
* 主內容的佈局。
*/
private View content;
private ListView listContent;
/**
* menu的佈局。
*/
private View menu;
private ListView listMenu;
/**
* menu佈局的參數,通過此參數來更改leftMargin的值。
*/
private LinearLayout.LayoutParams menuParams;
/**
* 記錄手指按下時的橫座標。
*/
private float xDown;
/**
* 記錄手指移動時的橫座標。
*/
private float xMove;
/**
* 記錄手機擡起時的橫座標。
*/
private float xUp;
/**
* menu當前是顯示還是隱藏。只有完全顯示或隱藏menu時纔會更改此值,滑動過程中此值無效。
*/
private boolean isMenuVisible;
/**
* 用於計算手指滑動的速度。
*/
private VelocityTracker mVelocityTracker;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initValues();
content.setOnTouchListener(this);
boolean flag = false;
listContent.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
TextView text2 = (TextView) arg1.findViewById(R.id.text2);
if (text2.getVisibility() == View.GONE)
text2.setVisibility(View.VISIBLE);
else
text2.setVisibility(View.GONE);
}
});
}
/**
* 初始化一些關鍵性數據。包括獲取屏幕的寬度,給content佈局重新設置寬度,給menu佈局重新設置寬度和偏移距離等。
*/
private void initValues() {
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
screenWidth = window.getDefaultDisplay().getWidth();
content = findViewById(R.id.content);
listContent = (ListView) findViewById(R.id.list_content);
listMenu = (ListView) findViewById(R.id.list_menu);
List<HashMap<String, String>> list = new ArrayList<HashMap<String, String>>();
for (int i = 0; i < 15; i++) {
HashMap<String, String> map = new HashMap<String, String>();
map.put("title", "側滑、摺疊效果 0" + i);
map.put("title1",
"初始化一些關鍵性數據。包括獲取屏幕的寬度,給content佈局重新設置寬度,給menu佈局重新設置寬度和偏移距離,初始化一些關鍵性數據。包括獲取屏幕的寬度,給content佈局重新設置寬度,給menu佈局重新設置寬度和偏移距離,初始化一些關鍵性數據。包括獲取屏幕的寬度,給content佈局重新設置寬度,給menu佈局重新設置寬度和偏移距離");
list.add(map);
}
SimpleAdapter adapter = new SimpleAdapter(this, list, R.layout.text,
new String[] { "title", "title1" }, new int[] { R.id.text1,
R.id.text2 });
listContent.setAdapter(adapter);
menu = findViewById(R.id.menu);
List<String> list1 = new ArrayList<String>();
list1.add("內容1");
list1.add("內容2");
list1.add("內容3");
list1.add("內容4");
ArrayAdapter<String> adapter1 = new ArrayAdapter<String>(this,
android.R.layout.simple_list_item_1, list1);
listMenu.setAdapter(adapter1);
menuParams = (LinearLayout.LayoutParams) menu.getLayoutParams();
// 將menu的寬度設置爲屏幕寬度減去menuPadding
menuParams.width = screenWidth - menuPadding;
// 左邊緣的值賦值爲menu寬度的負數
leftEdge = -menuParams.width;
// menu的leftMargin設置爲左邊緣的值,這樣初始化時menu就變爲不可見
menuParams.leftMargin = leftEdge;
// 將content的寬度設置爲屏幕寬度
content.getLayoutParams().width = screenWidth;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
createVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 手指按下時,記錄按下時的橫座標
xDown = event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
// 手指移動時,對比按下時的橫座標,計算出移動的距離,來調整menu的leftMargin值,從而顯示和隱藏menu
xMove = event.getRawX();
int distanceX = (int) (xMove - xDown);
if (isMenuVisible) {
menuParams.leftMargin = distanceX;
} else {
menuParams.leftMargin = leftEdge + distanceX;
}
if (menuParams.leftMargin < leftEdge) {
menuParams.leftMargin = leftEdge;
} else if (menuParams.leftMargin > rightEdge) {
menuParams.leftMargin = rightEdge;
}
Log.i("Left Margin", menuParams.leftMargin + "");
menu.setLayoutParams(menuParams);
break;
case MotionEvent.ACTION_UP:
// 手指擡起時,進行判斷當前手勢的意圖,從而決定是滾動到menu界面,還是滾動到content界面
xUp = event.getRawX();
if (wantToShowMenu()) {
if (shouldScrollToMenu()) {
scrollToMenu();
} else {
scrollToContent();
}
} else if (wantToShowContent()) {
if (shouldScrollToContent()) {
scrollToContent();
} else {
scrollToMenu();
}
}
recycleVelocityTracker();
break;
}
return true;
}
/**
* 判斷當前手勢的意圖是不是想顯示content。如果手指移動的距離是負數,且當前menu是可見的,則認爲當前手勢是想要顯示content。
*
* @return 當前手勢想顯示content返回true,否則返回false。
*/
private boolean wantToShowContent() {
return xUp - xDown < 0 && isMenuVisible;
}
/**
* 判斷當前手勢的意圖是不是想顯示menu。如果手指移動的距離是正數,且當前menu是不可見的,則認爲當前手勢是想要顯示menu。
*
* @return 當前手勢想顯示menu返回true,否則返回false。
*/
private boolean wantToShowMenu() {
return xUp - xDown > 0 && !isMenuVisible;
}
/**
* 判斷是否應該滾動將menu展示出來。如果手指移動距離大於屏幕的1/2,或者手指移動速度大於SNAP_VELOCITY,
* 就認爲應該滾動將menu展示出來。
*
* @return 如果應該滾動將menu展示出來返回true,否則返回false。
*/
private boolean shouldScrollToMenu() {
return xUp - xDown > screenWidth / 2
|| getScrollVelocity() > SNAP_VELOCITY;
}
/**
* 判斷是否應該滾動將content展示出來。如果手指移動距離加上menuPadding大於屏幕的1/2,
* 或者手指移動速度大於SNAP_VELOCITY, 就認爲應該滾動將content展示出來。
*
* @return 如果應該滾動將content展示出來返回true,否則返回false。
*/
private boolean shouldScrollToContent() {
return xDown - xUp + menuPadding > screenWidth / 2
|| getScrollVelocity() > SNAP_VELOCITY;
}
/**
* 將屏幕滾動到menu界面,滾動速度設定爲30.
*/
private void scrollToMenu() {
new ScrollTask().execute(30);
}
/**
* 將屏幕滾動到content界面,滾動速度設定爲-30.
*/
private void scrollToContent() {
new ScrollTask().execute(-30);
}
/**
* 創建VelocityTracker對象,並將觸摸content界面的滑動事件加入到VelocityTracker當中。
*
* @param event
* content界面的滑動事件
*/
private void createVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}
/**
* 獲取手指在content界面滑動的速度。
*
* @return 滑動速度,以每秒鐘移動了多少像素值爲單位。
*/
private int getScrollVelocity() {
mVelocityTracker.computeCurrentVelocity(1000);
int velocity = (int) mVelocityTracker.getXVelocity();
return Math.abs(velocity);
}
/**
* 回收VelocityTracker對象。
*/
private void recycleVelocityTracker() {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
class ScrollTask extends AsyncTask<Integer, Integer, Integer> {
@Override
protected Integer doInBackground(Integer... speed) {
int leftMargin = menuParams.leftMargin;
// 根據傳入的速度來滾動界面,當滾動到達左邊界或右邊界時,跳出循環。
while (true) {
leftMargin = leftMargin + speed[0];
if (leftMargin > rightEdge) {
leftMargin = rightEdge;
break;
}
if (leftMargin < leftEdge) {
leftMargin = leftEdge;
break;
}
publishProgress(leftMargin);
// 爲了要有滾動效果產生,每次循環使線程睡眠20毫秒,這樣肉眼才能夠看到滾動動畫。
sleep(20);
}
if (speed[0] > 0) {
isMenuVisible = true;
} else {
isMenuVisible = false;
}
return leftMargin;
}
@Override
protected void onProgressUpdate(Integer... leftMargin) {
menuParams.leftMargin = leftMargin[0];
menu.setLayoutParams(menuParams);
}
@Override
protected void onPostExecute(Integer leftMargin) {
menuParams.leftMargin = leftMargin;
menu.setLayoutParams(menuParams);
}
}
/**
* 使當前線程睡眠指定的毫秒數。
*
* @param millis
* 指定當前線程睡眠多久,以毫秒爲單位
*/
private void sleep(long millis) {
try {
Thread.sleep(millis);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
@轉載請註明出處http://blog.csdn.net/zjbpku/