Android Custom Realization of Side Slip Menu Effect

  • 2021-11-01 04:41:53
  • OfStack

This article example for everyone to share the Android custom implementation of the side slip menu specific code, for your reference, the specific content is as follows

Implementation principle: Inheriting ViewGroup controls to be displayed on the interface requires rewriting OnMeature ()
OnLayout (), so when OnLayout () is realized, the menu interface is drawn to the left side of the screen, and the sliding effect can be realized by dynamically changing the distance between the menu interface and the left boundary of scrollXto ().

1. Inherit ViewGroup
2. Event distribution mechanism
3. Status Monitoring

Add two child controls in the main interface


<com.oblivion.ui.SlideMenu xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/sliding_menu"
  android:layout_width="match_parent"
  android:layout_height="match_parent">

  <!--  In SlidingMenu Index in 0 -->
  <include layout="@layout/menu" />

  <!--  In SlidingMenu Index in 1 -->
  <include layout="@layout/main" />

</com.oblivion.ui.SlideMenu>

menu menu layout


<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="240dp"
  android:layout_height="match_parent"
  android:background="@drawable/menu_bg">

  <LinearLayout
    android:layout_width="240dp"
    android:layout_height="wrap_content"
    android:orientation="vertical">

    <TextView
      android:id="@+id/tv_news"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:background="@drawable/select_menu"
      android:clickable="true"
      android:drawableLeft="@drawable/tab_news"
      android:drawablePadding="10dp"
      android:text=" News " />

    <TextView
      android:id="@+id/tv_read"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_read"
      android:drawablePadding="10dp"
      android:text=" Subscribe " />

    <TextView
      android:id="@+id/tv_local"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_local"
      android:drawablePadding="10dp"
      android:text=" Local " />

    <TextView
      android:id="@+id/tv_ties"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_ties"
      android:drawablePadding="10dp"
      android:text=" Follow-up post " />

    <TextView
      android:id="@+id/tv_pics"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_pics"
      android:drawablePadding="10dp"
      android:text=" Picture " />

    <TextView
      android:id="@+id/tv_ugc"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_ugc"
      android:drawablePadding="10dp"
      android:text=" Topic " />

    <TextView
      android:id="@+id/tv_vote"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_vote"
      android:drawablePadding="10dp"
      android:text=" Vote " />

    <TextView
      android:id="@+id/tv_focus"
      style="@style/menu_item"
      android:layout_width="match_parent"
      android:layout_height="wrap_content"
      android:drawableLeft="@drawable/tab_focus"
      android:drawablePadding="10dp"
      android:text=" Focus " />
  </LinearLayout>
</ScrollView>

Display interface layout


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  android:layout_width="match_parent"
  android:layout_height="match_parent"
  android:orientation="vertical">

  <LinearLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:background="@drawable/top_bar_bg"
    android:orientation="horizontal">

    <ImageView
      android:id="@+id/iv_showmenu"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:src="@drawable/main_back" />

    <View
      android:layout_width="1dp"
      android:layout_height="match_parent"
      android:background="@drawable/top_bar_divider"></View>

    <TextView
      android:layout_width="match_parent"
      android:layout_height="match_parent"
      android:gravity="center"
      android:text=" News front page "
      android:textColor="#ffffff"
      android:textSize="30sp" />
  </LinearLayout>

  <TextView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center_horizontal"
    android:text=" Fuck, so low"
    android:textColor="#000000"
    android:textSize="20sp" />


</LinearLayout>

Implementation principle: OnMeature () OnLayout () is needed to be rewritten to display ViewGroup control on the interface. Therefore, when OnLayout () is realized, the menu interface is drawn to the left side of the screen, and the sliding effect can be realized by dynamically changing the distance between the menu interface and the left boundary of scrollXto ().

Implement onMeasure () and onLayout () methods to lay out controls


/**
   *  Measuring Controls in Layout 
   *
   * @param widthMeasureSpec
   * @param heightMeasureSpec
   */
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    super.onMeasure(widthMeasureSpec, heightMeasureSpec);// Measure its own width and height 
    // Get menu Interface 
    menuView = getChildAt(0);
    menuViewWidth = menuView.getLayoutParams().width;
    // Get main Interface 
    mainView = getChildAt(1);
    // Setting menuView Width of ------ No need setMeasure...
    menuView.measure(MeasureSpec.makeMeasureSpec(menuViewWidth, MeasureSpec.EXACTLY), heightMeasureSpec);
    // Setting mainView Width of 
    mainView.measure(widthMeasureSpec, heightMeasureSpec);
  }

  @Override
  protected void onLayout(boolean changed, int l, int t, int r, int b) {

    int menuleft = -menuViewWidth;//menu Set left
    int menuright = 0;//menu Set right
    int menutop = 0;//menu Set top
    int menubottom = b - t;//menu Set bottom
    // Layout menuView  Control xx2
    menuView.layout(menuleft, menutop, menuright, menubottom);
    int mainleft = 0;//main Set left
    int mainright = r - l;//main Set right
    int maintop = 0;//main Set top
    int mainbottom = b - t;//main Set bottom
    // Layout mainView --------------- Control ..... Your mother forced her way --------- The direction is left,top,right,bottom
    mainView.layout(mainleft, maintop, mainright, mainbottom);
    System.out.println(menuViewWidth--);// It turns out that this has been reduced here; 

  }

The boundary value is obtained by onTouch () method, scrollX () and getScrollX () method, and dynamically changed to realize sliding.
Note here that scrollX () and getScrollX () get values relative to the starting point of the layout, so they need to be re-encapsulated;
To smooth animation, it is necessary to create an Scroll class in the constructor, and then judge whether the set smooth animation is over through the ComplentScroll... method.

Finally, through the boundary value after the animation, judge whether it is open or closed.


 /**
   *  Due to the system scrollTo Is a reverse operation, so it needs to be encapsulated 1 Under 
   *
   * @param distance
   */
  private void scrollTo(int distance) {
    super.scrollTo(-distance, 0);
  }

  public int getMyScrollX() {
    return -getScrollX();
  }

  /**
   *  Control touch state 
   *
   * @param event
   * @return
   */
  @Override
  public boolean onTouchEvent(MotionEvent event) {
    switch (event.getAction()) {
      case MotionEvent.ACTION_DOWN:
        // Record the press point 
        down_dot = (int) event.getX();
        System.out.println(down_dot);
        break;
      case MotionEvent.ACTION_MOVE:
        int move_dot = (int) event.getX();
        // Absolute value of the distance between dynamic moving points and pressed points 
        move2down_distance = move_dot - down_dot;
        // Move spacing and last lifted point 
        int lastUp_dot = move2down_distance + up_dot;
        //  Control boundary 
        if (lastUp_dot >= menuViewWidth) {
          lastUp_dot = menuViewWidth;
        } else if (lastUp_dot <= 0) {
          lastUp_dot = 0;
        }
        // Set the distance after moving 
        scrollTo(lastUp_dot);
        break;
      case MotionEvent.ACTION_UP:
        // Presently lift your finger point 
        up_dot = (int) event.getX();
        // Set the final state 
        setFinalScroll();
        break;
    }
    return true;// Consumption of Events 
  }

  /**
   *  When the finger is lifted, record the final state; 
   */
  private void setFinalScroll() {
    // Get the distance from the left boundary of the current distance 
    currrentScroll = getMyScrollX();
    if (currrentScroll >= menuViewWidth / 2) {
      //scrollTo(menuViewWidth);
      rightAnimation();
    } else {
      leftAnimation();

    }
  }

  /**
   *  Smooth moving left animation 
   */
  private void leftAnimation() {
    //scrollTo(0);
    int dx = 0 - currrentScroll;// The distance to move 
    // Set Smooth Animation 
    msScroller.startScroll(currrentScroll, 0, dx, 0, 300);
    invalidate();
    // Setting 1 Lower lifting point 
    up_dot = 0;
    // Calling the closed state of the interface 
    mOnDragStateListener.onDragClose();
  }
  /**
   *  Animation that moves smoothly to the right 
   */
  private void rightAnimation() {
    int dx = menuViewWidth - currrentScroll;// The distance to move 
    // Set Smooth Animation 
    msScroller.startScroll(currrentScroll, 0, dx, 0, 300);
    invalidate();
    // Setting 1 Lower lifting point 
    up_dot = menuViewWidth;
    // Invoke the open state of the interface 
    mOnDragStateListener.onDragOpen();
  }

  /**
   *  Does the smooth move animation end 
   */
  @Override
  public void computeScroll() {
    super.computeScroll();
    if (msScroller.computeScrollOffset()) {
      int currX = msScroller.getCurrX();// The simulated value 
      scrollTo(currX);
      invalidate();
    }
  }

Create listening and callback interfaces


 /**
   *  Drag-and-drop monitoring 
   */
  public void setOnDragStateListener(onDragStateListener listener) {
    mOnDragStateListener = listener;
  }

  /**
   *  Callback modification status 
   *
   * @param dragState
   */
  public void setStateChange(boolean dragState) {
    if (dragState) {
      currrentScroll = 0;
      rightAnimation();
    } else {
      currrentScroll = menuViewWidth;
      leftAnimation();
    }
  }


  /**
   *  Create a drag-and-drop callback interface 
   */
  public interface onDragStateListener {
    /**
     *  Be dragged away 
     */
    void onDragOpen();

    /**
     *  Be shut down 
     */
    void onDragClose();
  }

Implementation of monitoring effect in main Activity


iv_showmenu.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        // After the picture clicks, it triggers to change the state 
        sliding_menu.setStateChange(dragState);
      }
    });
    sliding_menu.setOnDragStateListener(new SlideMenu.onDragStateListener() {
      @Override
      public void onDragOpen() {
        ToastUtils.setToast(getApplicationContext(), "open");
        dragState = false;
        tv_news.setSelected(true);
        tv_news.setTextColor(Color.BLUE);
      }

      @Override
      public void onDragClose() {
        ToastUtils.setToast(getApplicationContext(), "close");
        dragState = true;
        tv_news.setSelected(false);
        tv_news.setTextColor(Color.WHITE);
      }
    });
    tv_news.setOnClickListener(new View.OnClickListener() {
      @Override
      public void onClick(View v) {
        ToastUtils.setToast(getApplicationContext(), tv_news.getText().toString());
      }
    });
  }

github source address


Related articles: