SoFunction
Updated on 2025-03-01

Android implements two-way swipe of up and down menus

This article shares the specific code for Android to realize two-way sliding of up and down menus for your reference. The specific content is as follows

This is a study of the up and down two-way sliding effect achieved by the online masters sliding left and right. Interested friends can read the code below. The annotation is very detailed. The principle is to display and hide the upper and lower layouts according to the direction of the finger sliding. The onTouch method is mainly used to obtain the sliding distance for offset.

import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
import ;
 
public class UpAndDownSlidinglayout extends RelativeLayout implements OnTouchListener{
 /**
  * The speed required for finger swiping to achieve when scrolling to show and hide the upper layout.
  */
 public static final int SNAP_VELOCITY = 200;
 
 /**
  * A type of sliding state means that no sliding is performed.
  */
 public static final int DO_NOTHING = 0;
 /**
  * A type of sliding state indicates that the upper side menu is being slided out.
  */
 public static final int SHOW_UP_MENU = 1;
 
 /**
  * A type of sliding state indicates that the menu on the lower side is sliding out.
  */
 public static final int SHOW_DOWN_MENU = 2;
 
 /**
  * A type of sliding state, indicating that the upper side menu is being hidden.
  */
 public static final int HIDE_UP_MENU = 3;
 
 /**
  * A type of sliding state, indicating that the menu on the lower side is being hidden.
  */
 public static final int HIDE_DOWN_MENU = 4;
 
 /**
  * Record the current sliding status
  */
 private int slideState;
 
 /**
  * Screen width value.
  */
 private int screenWidth;
 private int screenHeight;
 
 /**
  * The maximum value the user's finger can move before it is determined to be scrolling.
  */
 private int touchSlop;
 
 /**
  * Record the horizontal coordinate when the finger is pressed.
  */
 private float xDown;
 
 /**
  * Record the vertical coordinate when the finger is pressed.
  */
 private float yDown;
 
 /**
  * Record the horizontal coordinates of the fingers when they move.
  */
 private float xMove;
 
 /**
  * Record the vertical coordinates of the fingers when they move.
  */
 private float yMove;
 
 /**
  * Record the vertical coordinate when the phone is lifted.
  */
 private float yUp;
 /**
  * Is the upper side menu currently displayed or hidden.  This value is changed only when fully displayed or hidden, and this value is invalid during sliding.
  */
 private boolean isUpMenuVisible;
 
 /**
  * Is the menu below currently displayed or hidden.  This value is changed only when fully displayed or hidden, and this value is invalid during sliding.
  */
 private boolean isDownMenuVisible;
 
 /**
  * Whether it is sliding.
  */
 private boolean isSliding;
 
 /**
  * The upper menu layout object.
  */
 private View upMenuLayout;
 
 /**
  * The menu layout object on the lower side.
  */
 private View downMenuLayout;
 
 /**
  * Content layout object.
  */
 private View contentLayout;
 
 /**
  * View used to listen for sliding events.
  */
 private View mBindView;
 
 /**
  * Parameters of the menu layout on the upper side.
  */
 private MarginLayoutParams upMenuLayoutParams;
 
 /**
  * Parameters of the menu layout on the lower side.
  */
 private MarginLayoutParams downMenuLayoutParams;
 
 /**
  * Parameters of content layout.
  */
 private  contentLayoutParams;
 
 /**
  * Used to calculate the speed of finger sliding.
  */
 private VelocityTracker mVelocityTracker;
 
 public UpAndDownSlidinglayout(Context context, AttributeSet attrs) {
 super(context, attrs);
 WindowManager wm = (WindowManager) (Context.WINDOW_SERVICE);
 screenWidth = ().getWidth();
 screenHeight = ().getHeight();
 touchSlop = (context).getScaledTouchSlop();
 }
 /**
  * Bind View that listens to sliding events.
  *
  * @param bindView
  * View object that needs to be bound.
  */
 public void setScrollEvent(View bindView) {
 mBindView = bindView;
 (this);
 }
 @Override
 public boolean onTouch(View v, MotionEvent event) {
 // TODO Auto-generated method stub
 createVelocityTracker(event);
 switch (()) {
 case MotionEvent.ACTION_DOWN:
 // When the finger is pressed, record the coordinates when pressed xDown = ();
 yDown = ();
 // Initialize the sliding state to DO_NOTHING slideState = DO_NOTHING;
 break;
 case MotionEvent.ACTION_MOVE:
 xMove = ();
 yMove = ();
 int moveDistanceX = (int) (xMove - xDown);
 int moveDistanceY = (int) (yMove - yDown);
 // Check the current sliding status checkSlideState(moveDistanceX, moveDistanceY);
 switch (slideState) {
 case SHOW_UP_MENU:
  = -moveDistanceY;
 checkUpMenuBorder();
 (contentLayoutParams);
 break;
 case HIDE_UP_MENU:
  = - - moveDistanceY;
 checkUpMenuBorder();
 (contentLayoutParams);
 case SHOW_DOWN_MENU:
  = moveDistanceY;
 checkDownMenuBorder();
 (contentLayoutParams);
 break;
 case HIDE_DOWN_MENU:
  = - + moveDistanceY;
 checkDownMenuBorder();
 (contentLayoutParams);
 default:
 break;
 }
 
 break;
  case MotionEvent.ACTION_UP:
 yUp = ();
 int upDistanceY = (int) (yUp - yDown);
 if (isSliding) {
 // When your finger is raised, make a judgment on the intention of the current gesture 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) {
 // When the upper side menu is displayed, if the user clicks on the content part, directly scroll to the content interface scrollToContentFromUpMenu();
 } else if (upDistanceY < touchSlop && isDownMenuVisible) {
 // When the lower side menu is displayed, if the user clicks on the content part, directly scroll to the content interface scrollToContentFromDownMenu();
 }
 recycleVelocityTracker();
 break;
 }
 return true;
 }
 
 /**
  * Create a VelocityTracker object and add a touch event to VelocityTracker.
  *
  * @param event
  *
  */
 private void createVelocityTracker(MotionEvent event) {
 if (mVelocityTracker == null) {
 mVelocityTracker = ();
 }
 (event);
 }
 
 /**
  * According to the distance the finger moves, determine the slideState's slide state value, and then assign the slideState to the corresponding slide state value.
  *
  * @param moveDistanceX
  * Distance of horizontal movement
  * @param moveDistanceY
  * Distance of vertical movement
  */
 private void checkSlideState(int moveDistanceX, int moveDistanceY) {
 if(isUpMenuVisible){
 if (!isSliding && (moveDistanceY) >= touchSlop && moveDistanceY < 0) {
 isSliding = true;
 slideState = HIDE_UP_MENU;
 }
 }else if(isDownMenuVisible){
 if (!isSliding && (moveDistanceY) >= touchSlop && moveDistanceY > 0) {
 isSliding = true;
 slideState = HIDE_DOWN_MENU;
 }
 }else{
 if (!isSliding && (moveDistanceY) >= touchSlop && moveDistanceY > 0
  && (moveDistanceX) < touchSlop) {
 isSliding = true;
 slideState = SHOW_UP_MENU;
 (RelativeLayout.ALIGN_PARENT_TOP, 0);
 (RelativeLayout.ALIGN_PARENT_BOTTOM);
 (contentLayoutParams);
 // If the user wants to slide the upper side menu, display the upper side menu and hide the lower side menu. ();
 ();
 }else if(!isSliding && (moveDistanceY) >= touchSlop && moveDistanceY < 0
  && (moveDistanceX) < touchSlop){
 isSliding = true;
 slideState = SHOW_DOWN_MENU;
 (RelativeLayout.ALIGN_PARENT_BOTTOM, 0);
 (RelativeLayout.ALIGN_PARENT_TOP);
 (contentLayoutParams);
 // If the user wants to slide the lower side menu, display the lower side menu and hide the upper side menu. ();
 ();
 }
 }
 }
 
 /**
  * Check the boundary value of the upper menu during sliding to prevent the bound layout from sliding out of the screen.
  */
 private void checkUpMenuBorder() {
 if ( > 0) {
  = 0;
 } else if ( < -) {
  = -;
 }
 }
 /**
  * Check the boundary value of the lower menu during sliding to prevent the bound layout from sliding out of the screen.
  */
 private void checkDownMenuBorder() {
 if ( > 0) {
  = 0;
 } else if ( < -) {
  = -;
 }
 }
 /**
  * Determine whether you should scroll to display the upper menu.  If the finger moves a distance greater than 1/2 of the width of the upper menu, or the finger moves a speed greater than SNAP_VELOCITY,
  * I think that the upper menu should be displayed by scrolling.
  *
  * @return Return true if the upper side menu should be displayed, otherwise return false.
  */
 private boolean shouldScrollToUpMenu() {
 return yUp - yDown >  / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
  * Determine whether you should scroll to display the menu on the lower side.  If the finger moves a distance greater than 1/2 of the width of the menu on the lower side, or the finger moves a speed greater than SNAP_VELOCITY,
  * I think that the menu below should be displayed scrolling.
  *
  * @return Return true if the menu below should be displayed, otherwise return false.
  */
 private boolean shouldScrollToDownMenu() {
 return yDown - yUp >  / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
  * Determine whether you should scroll from the upper menu to the content layout. If the finger moves from the upper menu to the width of the upper menu, or the finger moves faster than SNAP_VELOCITY,
  * I think it should be scrolled from the upper menu to the content layout.
  *
  * @return Return true if it should be scrolled from the upper side menu to the content layout, otherwise return false.
  */
 private boolean shouldScrollToContentFromUpMenu() {
 return yDown - yUp >  / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 
 /**
  * Determine whether you should scroll from the lower menu to the content layout. If the finger moves from the lower menu to the width of the lower menu, or the finger moves faster than SNAP_VELOCITY,
  * I think it should be scrolled from the menu below to the content layout.
  *
  * @return Return true if it should be scrolled from the lower menu to the content layout, otherwise return false.
  */
 private boolean shouldScrollToContentFromDownMenu() {
 return yUp - yDown >  / 2 || getScrollVelocity() > SNAP_VELOCITY;
 }
 /**
  * Gets the sliding speed of the finger on the bound layout.
  *
  * @return Sliding speed, in units of how many pixels have moved per second.
  */
 private int getScrollVelocity() {
 (1000);
 int velocity = (int) ();
 return (velocity);
 }
 
 class UpMenuScrollTask extends AsyncTask<Integer, Integer, Integer> {
 
 @Override
 protected Integer doInBackground(Integer... speed) {
 int bottomMargin = ;
 // Scroll the interface according to the incoming speed, and when the scroll reaches the boundary value, the loop jumps out. while (true) {
 bottomMargin = bottomMargin + speed[0];
 if (bottomMargin < -) {
  bottomMargin = -;
  break;
 }
 if (bottomMargin > 0) {
  bottomMargin = 0;
  break;
 }
 publishProgress(bottomMargin);
 // In order to have a scrolling effect, each loop makes the thread sleep for a period of time so that the naked eye can see the scrolling animation. sleep(15);
 }
 if (speed[0] > 0) {
 isUpMenuVisible = false;
 } else {
 isUpMenuVisible = true;
 }
 isSliding = false;
 return bottomMargin;
 }
 
 @Override
 protected void onProgressUpdate(Integer... bottomMargin) {
  = bottomMargin[0];
 (contentLayoutParams);
 unFocusBindView();
 }
 
 @Override
 protected void onPostExecute(Integer bottomMargin) {
  = bottomMargin;
 (contentLayoutParams);
 }
 }
 
 class DownMenuScrollTask extends AsyncTask<Integer, Integer, Integer> {
 
 @Override
 protected Integer doInBackground(Integer... speed) {
 int topMargin = ;
 // Scroll the interface according to the incoming speed, and when the scroll reaches the boundary value, the loop jumps out. while (true) {
 topMargin = topMargin + speed[0];
 if (topMargin < -) {
  topMargin = -;
  break;
 }
 if (topMargin > 0) {
  topMargin = 0;
  break;
 }
 publishProgress(topMargin);
 // In order to have a scrolling effect, each loop makes the thread sleep for a period of time so that the naked eye can see the scrolling animation. sleep(15);
 }
 if (speed[0] > 0) {
 isDownMenuVisible = false;
 } else {
 isDownMenuVisible = true;
 }
 isSliding = false;
 return topMargin;
 }
 
 @Override
 protected void onProgressUpdate(Integer... topMargin) {
  = topMargin[0];
 (contentLayoutParams);
 unFocusBindView();
 }
 
 @Override
 protected void onPostExecute(Integer topMargin) {
  = topMargin;
 (contentLayoutParams);
 }
 }
 /**
  * Make the current thread sleep the specified number of milliseconds.
  *
  * @param millis
  * Specify how long the current thread sleeps, in milliseconds
  */
 private void sleep(long millis) {
 try {
 (millis);
 } catch (InterruptedException e) {
 ();
 }
 }
 /**
  * Use the control that can gain focus to lose focus while sliding.
  */
 private void unFocusBindView() {
 if (mBindView != null) {
 (false);
 (false);
 (false);
 }
 }
 
 /**
  * Scroll the interface to the upper menu interface, and set the scrolling speed to -30.
  */
 public void scrollToUpMenu() {
 new UpMenuScrollTask().execute(-30);
 }
 
 /**
  * Scroll the interface to the lower menu interface, and set the scrolling speed to -30.
  */
 public void scrollToDownMenu() {
 new DownMenuScrollTask().execute(-30);
 }
 
 /**
  * Scroll the interface from the upper menu to the content interface, and set the scrolling speed to 30.
  */
 public void scrollToContentFromUpMenu() {
 new UpMenuScrollTask().execute(30);
 }
 
 /**
  * Scroll the interface from the lower menu to the content interface, and set the scrolling speed to 30.
  */
 public void scrollToContentFromDownMenu() {
 new DownMenuScrollTask().execute(30);
 }
 
 /**
  * Whether the upper menu is fully displayed, this value is invalid during sliding.
  *
  * @return The upper side menu is fully displayed and returns true, otherwise it returns false.
  */
 public boolean isUpLayoutVisible() {
 return isUpMenuVisible;
 }
 
 /**
  * Whether the menu on the lower side is fully displayed, this value is invalid during sliding.
  *
  * @return The menu below is fully displayed and returns true, otherwise it returns false.
  */
 public boolean isDownLayoutVisible() {
 return isDownMenuVisible;
 }
 
 /**
  * Reset the parameters of the upper side menu, lower side menu, and content layout in onLayout.
  */
 @Override
 protected void onLayout(boolean changed, int l, int t, int r, int b) {
 (changed, l, t, r, b);
 if (changed) {
 // Get the layout object of the upper menu upMenuLayout = getChildAt(0);
 upMenuLayoutParams = (MarginLayoutParams) ();
 // Get the menu layout object on the bottom downMenuLayout = getChildAt(1);
 downMenuLayoutParams = (MarginLayoutParams) ();
 // Get the content layout object contentLayout = getChildAt(2);
 contentLayoutParams = () ();
  = screenHeight;
 (contentLayoutParams);
 }
 }
 /**
  * Recycle VelocityTracker objects.
  */
 private void recycleVelocityTracker() {
 ();
 mVelocityTracker = null;
 }
}

Here is an example of usage:

import ;
import ;
import ;
import ;
import ;
 
/**
  * Sliding menu Demo main activity
  *
  * @author guolin
  */
public class MainActivity2 extends Activity {
 
 /**
  * Two-way sliding menu layout
  */
 private UpAndDownSlidinglayout updownSldingLayout;
 
 /**
  * ListView displayed on content layout
  */
 private ListView contentList;
 private LinearLayout ll;
 /**
  * ListView adapter
  */
 private ArrayAdapter<String> contentListAdapter;
 
 /**
  * Data source used to populate 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) {
 (savedInstanceState);
 setContentView(.activity_main2);
 ll = (LinearLayout) findViewById();
 updownSldingLayout = (UpAndDownSlidinglayout) findViewById(.updown_sliding_layout);
 contentList = (ListView) findViewById();
 contentListAdapter = new ArrayAdapter<String>(this, .simple_list_item_1,
 contentItems);
 (contentListAdapter);
 (ll);
 }
 
}

Layout file:

< xmlns:andro
 xmlns:tools="/tools"
 android:
 android:layout_width="fill_parent"
 android:layout_height="fill_parent" >
 
 <RelativeLayout
  android:
  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:
  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:
  android:layout_width="fill_parent"
  android:layout_height="fill_parent"
  android:gravity="center"
  android:background="#e9e9e9" >
 
  <ListView
   android:
   android:layout_width="fill_parent"
   android:layout_height="500dp"
   android:scrollbars="none"
   android:cacheColorHint="#00000000" >
  </ListView>
 </LinearLayout>
 
</>

For more articles about the sliding function, please click on the topic:"Android Sliding Function"

The above is all the content of this article. I hope it will be helpful to everyone's study and I hope everyone will support me more.