1. 程式人生 > >Android側拉框的簡單實現

Android側拉框的簡單實現

介面很簡單

<LinearLayout 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" 
    android:orientation="horizontal">
    <LinearLayout
        android:id="@+id/menu"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#000000" 
        android:orientation="vertical">
        <ListView 
            android:id="@+id/menu_list"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:divider="#ffffff"
            android:dividerHeight="5dp">
        </ListView>
    </LinearLayout>
    <LinearLayout
        android:id="@+id/content"
        android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:background="#ffffff" 
        android:orientation="vertical">
        <TextView
             android:id="@+id/content_text"
            android:layout_width="fill_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:textSize="25sp"
            android:text="hello"/>
    </LinearLayout>
</LinearLayout>

具體程式碼實現

public class MainActivity extends Activity implements OnTouchListener,
OnItemClickListener {
/**
* 滾動顯示和隱藏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 = 250;


/**
* 主內容的佈局。
*/
private View content;


/**
* menu的佈局。
*/
private View menu;


/**
* menu佈局的引數,通過此引數來更改leftMargin的值。
*/
private LinearLayout.LayoutParams menuParams;


/**
* 記錄手指按下時的橫座標。
*/
private float xDown;


/**
* 記錄手指移動時的橫座標。
*/
private float xMove;


/**
* 記錄手機擡起時的橫座標。
*/
private float xUp;


/**
* menu當前是顯示還是隱藏。只有完全顯示或隱藏menu時才會更改此值,滑動過程中此值無效。
*/
private boolean isMenuVisible;


/**
* 用於計算手指滑動的速度。
*/
private VelocityTracker mVelocityTracker;
private ListView menu_list;
private TextView content_text;
private ArrayList list;
private SimpleAdapter adapter;


@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
initValues();
content.setOnTouchListener(this);
menu_list = (ListView) findViewById(R.id.menu_list);
content_text = (TextView) findViewById(R.id.content_text);
adapter = new SimpleAdapter(this, getData(), R.layout.menu_list,
new String[] { "text" }, new int[] { R.id.text });
menu_list.setAdapter(adapter);
menu_list.setOnItemClickListener(this);
}


private ArrayList getData() {
list = new ArrayList();
for (int i = 0; i < 8; i++) {
HashMap map = new HashMap();
map.put("text", "test view====" + i);
list.add(map);
}
return list;
}


private void initValues() {
WindowManager window = (WindowManager) getSystemService(Context.WINDOW_SERVICE);
screenWidth = window.getDefaultDisplay().getWidth();
menu = findViewById(R.id.menu);
content = findViewById(R.id.content);


menuParams = (LinearLayout.LayoutParams) menu.getLayoutParams();
menuParams.width = screenWidth - menuPadding;
leftEdge = -menuParams.width;
menuParams.leftMargin = leftEdge;
content.getLayoutParams().width = screenWidth;
}


@Override
public boolean onTouch(View v, MotionEvent event) {
createVelocityTracker(event);
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// 記錄手指按下時的x座標
xDown = event.getRawX();
break;
case MotionEvent.ACTION_MOVE:
// 記錄手指移動時的x座標
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;
}
menu.setLayoutParams(menuParams);
break;
case MotionEvent.ACTION_UP:
// 手指擡起時
xUp = event.getRawX();
if (wantToShowMenu()) {
if (shouldScrollToMenu()) {
scrollToMenu();
} else {
scrollToContent();
}
} else if (wantToShowContent()) {
if (shouldScrollToContent()) {
scrollToContent();
} else {
scrollToMenu();
}
}
recycleVelocityTracker();
break;
}
return true;
}


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


/**
* 將螢幕滾動到menu介面,滾動速度設定為30.
*/
private void scrollToMenu() {
new ScrollTask().execute(30);
}


/**
* 將螢幕滾動到content介面,滾動速度設定為-30.
*/
private void scrollToContent() {
new ScrollTask().execute(-30);
}


/**
* 判斷當前手勢的意圖是不是想顯示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 > menu.getWidth() / 2
|| getScrollVelocity() > SNAP_VELOCITY;
}


/**
* 判斷是否應該滾動將content展示出來。如果手指移動距離加上menuPadding大於螢幕的1/2,
* 或者手指移動速度大於SNAP_VELOCITY, 就認為應該滾動將content展示出來。

* @return 如果應該滾動將content展示出來返回true,否則返回false。
*/
private boolean shouldScrollToContent() {
return xDown - xUp + menuPadding > menu.getWidth() / 2
|| getScrollVelocity() > SNAP_VELOCITY;
}


/**
* 獲取手指在content介面滑動的速度。

* @return 滑動速度,以每秒鐘移動了多少畫素值為單位。
*/
private int getScrollVelocity() {
mVelocityTracker.computeCurrentVelocity(1000);
int velocity = (int) mVelocityTracker.getXVelocity();
return Math.abs(velocity);
}


/**
* 建立VelocityTracker物件,並將觸控content介面的滑動事件加入到VelocityTracker當中。

* @param event
*            content介面的滑動事件
*/
private void createVelocityTracker(MotionEvent event) {
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
}


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();
}
}
@Override
public void onItemClick(AdapterView<?> parent, View view, int position,
long id) {
HashMap map=(HashMap) adapter.getItem(position);
content_text.setText(map.get("text").toString());
}
}

再重新回顧一遍才發現,其實很多東西都沒想象的那麼難