中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

使用Android實現上下菜單雙向滑動效果

發布時間:2020-10-29 15:45:19 來源:億速云 閱讀:452 作者:Leah 欄目:開發技術

本篇文章給大家分享的是有關使用Android實現上下菜單雙向滑動效果,小編覺得挺實用的,因此分享給大家學習,希望大家閱讀完這篇文章后可以有所收獲,話不多說,跟著小編一起來看看吧。

主要用了onTouch方法,獲取滑動的距離進行偏移。

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.WindowManager;
import android.view.View.OnTouchListener;
import android.widget.RelativeLayout;
 
public class UpAndDownSlidinglayout extends RelativeLayout implements OnTouchListener{
 /**
 * 滾動顯示和隱藏上側布局時,手指滑動需要達到的速度。
 */
 public static final int SNAP_VELOCITY = 200;
 
 /**
 * 滑動狀態的一種,表示未進行任何滑動。
 */
 public static final int DO_NOTHING = 0;
 /**
 * 滑動狀態的一種,表示正在滑出上側菜單。
 */
 public static final int SHOW_UP_MENU = 1;
 
 /**
 * 滑動狀態的一種,表示正在滑出下側菜單。
 */
 public static final int SHOW_DOWN_MENU = 2;
 
 /**
 * 滑動狀態的一種,表示正在隱藏上側菜單。
 */
 public static final int HIDE_UP_MENU = 3;
 
 /**
 * 滑動狀態的一種,表示正在隱藏下側菜單。
 */
 public static final int HIDE_DOWN_MENU = 4;
 
 /**
 * 記錄當前的滑動狀態
 */
 private int slideState;
 
 /**
 * 屏幕寬度值。
 */
 private int screenWidth;
 private int screenHeight;
 
 /**
 * 在被判定為滾動之前用戶手指可以移動的最大值。
 */
 private int touchSlop;
 
 /**
 * 記錄手指按下時的橫坐標。
 */
 private float xDown;
 
 /**
 * 記錄手指按下時的縱坐標。
 */
 private float yDown;
 
 /**
 * 記錄手指移動時的橫坐標。
 */
 private float xMove;
 
 /**
 * 記錄手指移動時的縱坐標。
 */
 private float yMove;
 
 /**
 * 記錄手機抬起時的縱坐標。
 */
 private float yUp;
 /**
 * 上側菜單當前是顯示還是隱藏。只有完全顯示或隱藏時才會更改此值,滑動過程中此值無效。
 */
 private boolean isUpMenuVisible;
 
 /**
 * 下側菜單當前是顯示還是隱藏。只有完全顯示或隱藏時才會更改此值,滑動過程中此值無效。
 */
 private boolean isDownMenuVisible;
 
 /**
 * 是否正在滑動。
 */
 private boolean isSliding;
 
 /**
 * 上側菜單布局對象。
 */
 private View upMenuLayout;
 
 /**
 * 下側菜單布局對象。
 */
 private View downMenuLayout;
 
 /**
 * 內容布局對象。
 */
 private View contentLayout;
 
 /**
 * 用于監聽滑動事件的View。
 */
 private View mBindView;
 
 /**
 * 上側菜單布局的參數。
 */
 private MarginLayoutParams upMenuLayoutParams;
 
 /**
 * 下側菜單布局的參數。
 */
 private MarginLayoutParams downMenuLayoutParams;
 
 /**
 * 內容布局的參數。
 */
 private RelativeLayout.LayoutParams contentLayoutParams;
 
 /**
 * 用于計算手指滑動的速度。
 */
 private VelocityTracker mVelocityTracker;
 
 public UpAndDownSlidinglayout(Context context, AttributeSet attrs) {
 super(context, attrs);
 WindowManager wm = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE);
 screenWidth = wm.getDefaultDisplay().getWidth();
 screenHeight = wm.getDefaultDisplay().getHeight();
 touchSlop = ViewConfiguration.get(context).getScaledTouchSlop();
 }
 /**
 * 綁定監聽滑動事件的View。
 * 
 * @param bindView
 *   需要綁定的View對象。
 */
 public void setScrollEvent(View bindView) {
 mBindView = bindView;
 mBindView.setOnTouchListener(this);
 }
 @Override
 public boolean onTouch(View v, MotionEvent event) {
 // TODO Auto-generated method stub
 createVelocityTracker(event);
 switch (event.getAction()) {
 case MotionEvent.ACTION_DOWN:
 // 手指按下時,記錄按下時的坐標
 xDown = event.getRawX();
 yDown = event.getRawY();
 // 將滑動狀態初始化為DO_NOTHING
 slideState = DO_NOTHING;
 break;
 case MotionEvent.ACTION_MOVE:
 xMove = event.getRawX();
 yMove = event.getRawY();
 int moveDistanceX = (int) (xMove - xDown);
 int moveDistanceY = (int) (yMove - yDown);
 // 檢查當前的滑動狀態
 checkSlideState(moveDistanceX, moveDistanceY);
 switch (slideState) {
 case SHOW_UP_MENU:
 contentLayoutParams.bottomMargin = -moveDistanceY;
 checkUpMenuBorder();
 contentLayout.setLayoutParams(contentLayoutParams);
 break;
 case HIDE_UP_MENU:
 contentLayoutParams.bottomMargin = -upMenuLayoutParams.height - moveDistanceY;
 checkUpMenuBorder();
 contentLayout.setLayoutParams(contentLayoutParams);
 case SHOW_DOWN_MENU:
 contentLayoutParams.topMargin = moveDistanceY;
 checkDownMenuBorder();
 contentLayout.setLayoutParams(contentLayoutParams);
 break;
 case HIDE_DOWN_MENU:
 contentLayoutParams.topMargin = -downMenuLayoutParams.height + moveDistanceY;
 checkDownMenuBorder();
 contentLayout.setLayoutParams(contentLayoutParams);
 default:
 break;
 }
 
 break;
  case MotionEvent.ACTION_UP:
 yUp = event.getRawY();
 int upDistanceY = (int) (yUp - yDown);
 if (isSliding) {
 // 手指抬起時,進行判斷當前手勢的意圖
 switch (slideState) {
 case SHOW_UP_MENU:
  if (shouldScrollToUpMenu()) {
  scrollToUpMenu();
  } else {
  scrollToContentFromUpMenu();
  }
  break;
 case HIDE_UP_MENU:
  if (shouldScrollToContentFromUpMenu()) {
  scrollToContentFromUpMenu();
  } else {
  scrollToUpMenu();
  }
  break;
 case SHOW_DOWN_MENU:
  if (shouldScrollToDownMenu()) {
  scrollToDownMenu();
  } else {
  scrollToContentFromDownMenu();
  }
  break;
 case HIDE_DOWN_MENU:
  if (shouldScrollToContentFromDownMenu()) {
  scrollToContentFromDownMenu();
  } else {
  scrollToDownMenu();
  }
  break;
 default:
  break;
 }
 }else if (upDistanceY < touchSlop && isUpMenuVisible) {
 // 當上側菜單顯示時,如果用戶點擊一下內容部分,則直接滾動到內容界面
 scrollToContentFromUpMenu();
 } else if (upDistanceY < touchSlop && isDownMenuVisible) {
 // 當下側菜單顯示時,如果用戶點擊一下內容部分,則直接滾動到內容界面
 scrollToContentFromDownMenu();
 }
 recycleVelocityTracker();
 break;
 }
 return true;
 }
 
 /**
 * 創建VelocityTracker對象,并將觸摸事件加入到VelocityTracker當中。
 * 
 * @param event
 *   
 */
 private void createVelocityTracker(MotionEvent event) {
 if (mVelocityTracker == null) {
 mVelocityTracker = VelocityTracker.obtain();
 }
 mVelocityTracker.addMovement(event);
 }
 
 /**
 * 根據手指移動的距離,判斷當前用戶的滑動意圖,然后給slideState賦值成相應的滑動狀態值。
 * 
 * @param moveDistanceX
 *   橫向移動的距離
 * @param moveDistanceY
 *   縱向移動的距離
 */
 private void checkSlideState(int moveDistanceX, int moveDistanceY) {
 if(isUpMenuVisible){
 if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY < 0) {
 isSliding = true;
 slideState = HIDE_UP_MENU;
 }
 }else if(isDownMenuVisible){
 if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY > 0) {
 isSliding = true;
 slideState = HIDE_DOWN_MENU;
 }
 }else{
 if (!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY > 0
  && Math.abs(moveDistanceX) < touchSlop) {
 isSliding = true;
 slideState = SHOW_UP_MENU;
 contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP, 0);
 contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
 contentLayout.setLayoutParams(contentLayoutParams);
 // 如果用戶想要滑動上側菜單,將上側菜單顯示,下側菜單隱藏
 upMenuLayout.setVisibility(View.VISIBLE);
 downMenuLayout.setVisibility(View.GONE);
 }else if(!isSliding && Math.abs(moveDistanceY) >= touchSlop && moveDistanceY < 0
  && Math.abs(moveDistanceX) < touchSlop){
 isSliding = true;
 slideState = SHOW_DOWN_MENU;
 contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM, 0);
 contentLayoutParams.addRule(RelativeLayout.ALIGN_PARENT_TOP);
 contentLayout.setLayoutParams(contentLayoutParams);
 // 如果用戶想要滑動下側菜單,將下側菜單顯示,上側菜單隱藏
 upMenuLayout.setVisibility(View.GONE);
 downMenuLayout.setVisibility(View.VISIBLE);
 }
 }
 }
 
 /**
 * 在滑動過程中檢查上側菜單的邊界值,防止綁定布局滑出屏幕。
 */
 private void checkUpMenuBorder() {
 if (contentLayoutParams.bottomMargin > 0) {
 contentLayoutParams.bottomMargin = 0;
 } else if (contentLayoutParams.bottomMargin < -upMenuLayoutParams.height) {
 contentLayoutParams.bottomMargin = -upMenuLayoutParams.height;
 }
 }
 /**
 * 在滑動過程中檢查下側菜單的邊界值,防止綁定布局滑出屏幕。
 */
 private void checkDownMenuBorder() {
 if (contentLayoutParams.topMargin > 0) {
 contentLayoutParams.topMargin = 0;
 } else if (contentLayoutParams.topMargin < -downMenuLayoutParams.height) {
 contentLayoutParams.topMargin = -downMenuLayoutParams.height;
 }
 }
 /**
 * 判斷是否應該滾動將上側菜單展示出來。如果手指移動距離大于上側菜單寬度的1/2,或者手指移動速度大于SNAP_VELOCITY,
 * 就認為應該滾動將上側菜單展示出來。
 * 
 * @return 如果應該將上側菜單展示出來返回true,否則返回false。
 */
 private boolean shouldScrollToUpMenu() {
 return yUp - yDown > upMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
 * 判斷是否應該滾動將下側菜單展示出來。如果手指移動距離大于下側菜單寬度的1/2,或者手指移動速度大于SNAP_VELOCITY,
 * 就認為應該滾動將下側菜單展示出來。
 * 
 * @return 如果應該將下側菜單展示出來返回true,否則返回false。
 */
 private boolean shouldScrollToDownMenu() {
 return yDown - yUp > downMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
 * 判斷是否應該從上側菜單滾動到內容布局,如果手指移動距離大于上側菜單寬度的1/2,或者手指移動速度大于SNAP_VELOCITY,
 * 就認為應該從上側菜單滾動到內容布局。
 * 
 * @return 如果應該從上側菜單滾動到內容布局返回true,否則返回false。
 */
 private boolean shouldScrollToContentFromUpMenu() {
 return yDown - yUp > upMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
 * 判斷是否應該從下側菜單滾動到內容布局,如果手指移動距離大于下側菜單寬度的1/2,或者手指移動速度大于SNAP_VELOCITY,
 * 就認為應該從下側菜單滾動到內容布局。
 * 
 * @return 如果應該從下側菜單滾動到內容布局返回true,否則返回false。
 */
 private boolean shouldScrollToContentFromDownMenu() {
 return yUp - yDown > downMenuLayoutParams.height / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 /**
 * 獲取手指在綁定布局上的滑動速度。
 * 
 * @return 滑動速度,以每秒鐘移動了多少像素值為單位。
 */
 private int getScrollVelocity() {
 mVelocityTracker.computeCurrentVelocity(1000);
 int velocity = (int) mVelocityTracker.getXVelocity();
 return Math.abs(velocity);
 }
 
 class UpMenuScrollTask extends AsyncTask<Integer, Integer, Integer> {
 
 @Override
 protected Integer doInBackground(Integer... speed) {
 int bottomMargin = contentLayoutParams.bottomMargin;
 // 根據傳入的速度來滾動界面,當滾動到達邊界值時,跳出循環。
 while (true) {
 bottomMargin = bottomMargin + speed[0];
 if (bottomMargin < -upMenuLayoutParams.height) {
  bottomMargin = -upMenuLayoutParams.height;
  break;
 }
 if (bottomMargin > 0) {
  bottomMargin = 0;
  break;
 }
 publishProgress(bottomMargin);
 // 為了要有滾動效果產生,每次循環使線程睡眠一段時間,這樣肉眼才能夠看到滾動動畫。
 sleep(15);
 }
 if (speed[0] > 0) {
 isUpMenuVisible = false;
 } else {
 isUpMenuVisible = true;
 }
 isSliding = false;
 return bottomMargin;
 }
 
 @Override
 protected void onProgressUpdate(Integer... bottomMargin) {
 contentLayoutParams.bottomMargin = bottomMargin[0];
 contentLayout.setLayoutParams(contentLayoutParams);
 unFocusBindView();
 }
 
 @Override
 protected void onPostExecute(Integer bottomMargin) {
 contentLayoutParams.bottomMargin = bottomMargin;
 contentLayout.setLayoutParams(contentLayoutParams);
 }
 }
 
 class DownMenuScrollTask extends AsyncTask<Integer, Integer, Integer> {
 
 @Override
 protected Integer doInBackground(Integer... speed) {
 int topMargin = contentLayoutParams.topMargin;
 // 根據傳入的速度來滾動界面,當滾動到達邊界值時,跳出循環。
 while (true) {
 topMargin = topMargin + speed[0];
 if (topMargin < -downMenuLayoutParams.height) {
  topMargin = -downMenuLayoutParams.height;
  break;
 }
 if (topMargin > 0) {
  topMargin = 0;
  break;
 }
 publishProgress(topMargin);
 // 為了要有滾動效果產生,每次循環使線程睡眠一段時間,這樣肉眼才能夠看到滾動動畫。
 sleep(15);
 }
 if (speed[0] > 0) {
 isDownMenuVisible = false;
 } else {
 isDownMenuVisible = true;
 }
 isSliding = false;
 return topMargin;
 }
 
 @Override
 protected void onProgressUpdate(Integer... topMargin) {
 contentLayoutParams.topMargin = topMargin[0];
 contentLayout.setLayoutParams(contentLayoutParams);
 unFocusBindView();
 }
 
 @Override
 protected void onPostExecute(Integer topMargin) {
 contentLayoutParams.topMargin = topMargin;
 contentLayout.setLayoutParams(contentLayoutParams);
 }
 }
 /**
 * 使當前線程睡眠指定的毫秒數。
 * 
 * @param millis
 *   指定當前線程睡眠多久,以毫秒為單位
 */
 private void sleep(long millis) {
 try {
 Thread.sleep(millis);
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 }
 /**
 * 使用可以獲得焦點的控件在滑動的時候失去焦點。
 */
 private void unFocusBindView() {
 if (mBindView != null) {
 mBindView.setPressed(false);
 mBindView.setFocusable(false);
 mBindView.setFocusableInTouchMode(false);
 }
 }
 
 /**
 * 將界面滾動到上側菜單界面,滾動速度設定為-30.
 */
 public void scrollToUpMenu() {
 new UpMenuScrollTask().execute(-30);
 }
 
 /**
 * 將界面滾動到下側菜單界面,滾動速度設定為-30.
 */
 public void scrollToDownMenu() {
 new DownMenuScrollTask().execute(-30);
 }
 
 /**
 * 將界面從上側菜單滾動到內容界面,滾動速度設定為30.
 */
 public void scrollToContentFromUpMenu() {
 new UpMenuScrollTask().execute(30);
 }
 
 /**
 * 將界面從下側菜單滾動到內容界面,滾動速度設定為30.
 */
 public void scrollToContentFromDownMenu() {
 new DownMenuScrollTask().execute(30);
 }
 
 /**
 * 上側菜單是否完全顯示出來,滑動過程中此值無效。
 * 
 * @return 上側菜單完全顯示返回true,否則返回false。
 */
 public boolean isUpLayoutVisible() {
 return isUpMenuVisible;
 }
 
 /**
 * 下側菜單是否完全顯示出來,滑動過程中此值無效。
 * 
 * @return 下側菜單完全顯示返回true,否則返回false。
 */
 public boolean isDownLayoutVisible() {
 return isDownMenuVisible;
 }
 
 /**
 * 在onLayout中重新設定上側菜單、下側菜單、以及內容布局的參數。
 */
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 super.onLayout(changed, l, t, r, b);
 if (changed) {
 // 獲取上側菜單布局對象
 upMenuLayout = getChildAt(0);
 upMenuLayoutParams = (MarginLayoutParams) upMenuLayout.getLayoutParams();
 // 獲取下側菜單布局對象
 downMenuLayout = getChildAt(1);
 downMenuLayoutParams = (MarginLayoutParams) downMenuLayout.getLayoutParams();
 // 獲取內容布局對象
 contentLayout = getChildAt(2);
 contentLayoutParams = (RelativeLayout.LayoutParams) contentLayout.getLayoutParams();
 contentLayoutParams.height = screenHeight;
 contentLayout.setLayoutParams(contentLayoutParams);
 }
 }
 /**
 * 回收VelocityTracker對象。
 */
 private void recycleVelocityTracker() {
 mVelocityTracker.recycle();
 mVelocityTracker = null;
 }
}

下面是使用實例:

import android.os.Bundle;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.app.Activity;
 
/**
 * 滑動菜單Demo主Activity
 * 
 * @author guolin
 */
public class MainActivity2 extends Activity {
 
 /**
 * 雙向滑動菜單布局
 */
 private UpAndDownSlidinglayout updownSldingLayout;
 
 /**
 * 在內容布局上顯示的ListView
 */
 private ListView contentList;
 private LinearLayout ll;
 /**
 * ListView的適配器
 */
 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_main2);
 ll = (LinearLayout) findViewById(R.id.content);
 updownSldingLayout = (UpAndDownSlidinglayout) findViewById(R.id.updown_sliding_layout);
 contentList = (ListView) findViewById(R.id.contentList);
 contentListAdapter = new ArrayAdapter<String>(this, android.R.layout.simple_list_item_1,
 contentItems);
 contentList.setAdapter(contentListAdapter);
 updownSldingLayout.setScrollEvent(ll);
 }
 
}

布局文件:

<com.example.UpAndDownSlidinglayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/updown_sliding_layout"
 android:layout_width="fill_parent"
 android:layout_height="fill_parent" >
 
 <RelativeLayout
  android:id="@+id/up_menu"
  android:layout_width="fill_parent"
  android:layout_height="300dp"
  android:layout_alignParentTop="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 up menu"
   android:textColor="#000000"
   android:textSize="28sp" />
 </RelativeLayout>
 
 <RelativeLayout
  android:id="@+id/down_menu"
  android:layout_width="fill_parent"
  android:layout_height="300dp"
  android:layout_alignParentBottom="true"
  android:background="#00ffcc"
  android:visibility="invisible" >
 
  <TextView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_centerInParent="true"
   android:text="This is down menu"
   android:textColor="#000000"
   android:textSize="28sp" />
 </RelativeLayout>
 
 <LinearLayout
  android:id="@+id/content"
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center"
  android:background="#e9e9e9" >
 
  <ListView
   android:id="@+id/contentList"
   android:layout_width="fill_parent"
   android:layout_height="500dp"
   android:scrollbars="none"
   android:cacheColorHint="#00000000" >
  </ListView>
 </LinearLayout>
 
</com.example.UpAndDownSlidinglayout>

以上就是使用Android實現上下菜單雙向滑動效果,小編相信有部分知識點可能是我們日常工作會見到或用到的。希望你能通過這篇文章學到更多知識。更多詳情敬請關注億速云行業資訊頻道。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

叙永县| 菏泽市| 慈溪市| 贡嘎县| 鄯善县| 宁蒗| 永仁县| 耒阳市| 东乌珠穆沁旗| 渭源县| 岑溪市| 鞍山市| 拉萨市| 东光县| 定南县| 从化市| 澄江县| 五台县| 池州市| 高要市| 汕尾市| 华亭县| 太保市| 黄平县| 弥勒县| 合江县| 遂宁市| 普安县| 五华县| 扎鲁特旗| 天祝| 邢台市| 连云港市| 多伦县| 玉屏| 沐川县| 湖州市| 秀山| 潢川县| 普兰店市| 囊谦县|