側滑、listView中摺疊效果的簡單實現方法

   

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>


text.xml:
<?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/

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章