Android custom slide conflict View--

1. The Custom View is the ViewGroup, the main interface and the interface Drawer slide, as shown below:

Custom View

View the complete code is as follows

public class SlideMenuextends ViewGroup {

    private View leftMenu;
    private View mainView;
    private float moveX;
    private float downX;
    private int curScrollPosition;
    private int cur_state = 0;//当前状态
    private static final int MAIN_STATE = 0;
    private static final int MENU_STATE = 1;
    private Scroller scroller;//滚动器
    private float downY;

    public SlideMenu(Context context) {
        super(context);
        initAnim();
    }
    
    public SlideMenu(Context context, AttributeSet attrs) {
        super(context, attrs);
        initAnim();
    }
    
    public SlideMenu(Context context, AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initAnim();
    }
    //初始化滚动器
    private void initAnim() {
        scroller = new Scroller(getContext());
    }
    
    /**
     * 测量并设置所有子View宽高
     * @param widthMeasureSpec:当前控件的宽度测量规则
     * @param heightMeasureSpec:当前控件的高度测量规则
     */
    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        //指定左面板的宽高
        leftMenu = getChildAt(0);//第一个子View
        //leftMenu.measure(leftMenu.getMeasuredWidth(), heightMeasureSpec);
        leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);
        //指定主面板的宽高
        mainView = getChildAt(1);//第二个子View
        mainView.measure(widthMeasureSpec, heightMeasureSpec);
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    }

    /**
     * b:当前控件的尺寸大小、位置是否发生了变化
     */
    @Override
    protected void onLayout(boolean isChanged, int l, int t, int r, int b) {
        //放置在侧滑面板(相对于左上角原点位置)
        leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b);
        mainView.layout(l, t, r, b);
    }

    /**
     *事件拦截
     */
    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //根据偏移量判断是否拦截
                float offsetX = Math.abs(event.getX() - downX);
                float offsetY = Math.abs(event.getY() - downY);
                if (offsetX > offsetY && offsetX > 5) {
                    return true;//拦截触摸事件,不往里传递,交个自己的OnTouchEvent处理
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(event);//默认不拦截
    }

    /**
     * 滚动屏幕,将View看做静的,屏幕是动的
     * scrollBy(x,y) :在原来位置基础上滚动了
     * scrollTo(x,y) : 滚动到(x,y)位置
     */
    @Override
    public boolean onTouchEvent(MotionEvent event) {

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();//按下时X坐标
                break;
            case MotionEvent.ACTION_MOVE:
                moveX = event.getX();//
                int x_change = (int) (downX - moveX);//x变化(偏移量)
                //当前要滚动的位置 = 之前滚动到的位置 + 偏移量
                curScrollPosition = getScrollX() + x_change;//最新滚动位置
                /**
                 *   考虑边界问题
                 */
                if (curScrollPosition > 0) {
                    scrollTo(0, 0);
                } else if (curScrollPosition < -leftMenu.getMeasuredWidth()) {
                    scrollTo(-leftMenu.getMeasuredWidth(), 0);
                } else {
                    scrollBy(x_change, 0);//(在范围内)滚动到当前位置
                }
                downX = moveX;//重要
                break;
            case MotionEvent.ACTION_UP:
                int menu_center = (int) (-leftMenu.getMeasuredWidth() / 2.0f);
                if (getScrollX() < menu_center) {
                    //打开
                    cur_state = MENU_STATE;
                } else {
                    cur_state = MAIN_STATE;
                }
                updateView(cur_state);
                break;
        }
        return true;//一定改成true(消费事件)
    }

    //滑动过程中松开手
    private void updateView(int cur_state) {
        int startX = getScrollX();//负数(当前滑动到的位置)
        int dx = 0;//将要移动的偏移量
        if (cur_state == MAIN_STATE) {//关闭
            dx = 0 - startX;
        } else {
            dx = -leftMenu.getMeasuredWidth() - startX;
        }
        //开始平滑的数据模拟
        int duration = Math.abs(dx * 2);
        //执行动画
        scroller.startScroll(startX, 0, dx, 0, duration);
        invalidate();//重绘界面:drawChild--computeScroll()
    }

    //维持动画
    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {//true动画没结束时(duration时间内)一直调用
            int currX = scroller.getCurrX();//获取当前的模拟值,要滚动的位置
            scrollTo(currX, 0);
            invalidate();//重绘->drawChild--computeScroll()
        }
    }
    //手动设置关闭菜单栏
    public void switcheDrawer() {
        if (cur_state == MAIN_STATE) {//主
            cur_state = MENU_STATE;
        } else {
            cur_state = MAIN_STATE;
        }
        updateView(cur_state);
    }
}

2. Custom Layout View

The view is a ViewGroup, there are two sub-View

    <!-- 这是一个ViewGroup ,里面两个子View-->
    <com.sliding.SlideMenu
        android:id="@+id/sm"
        android:layout_width="wrap_content"
        android:layout_height="match_parent">
   		<!-- 第一个子View-->
        <include layout="@layout/layout_menu_left"/>
   		<!--第两个子View-->
        <include layout="@layout/layout_main" />

    </com.sliding.SlideMenu>

3. Measure the width and height of the sub-View

Width and height were measured for all sub-View of ViewGroup

  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
      //测量第一个子View的宽高
      leftMenu = getChildAt(0);
      leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);
      //测量第二个子View的宽高
      mainView = getChildAt(1);
      mainView.measure(widthMeasureSpec, heightMeasureSpec);
      super.onMeasure(widthMeasureSpec, heightMeasureSpec);
  }

4. Place each sub-View

	@Override
	protected void onLayout(boolean isChanged, int l, int t, int r, int b) {
	    //第一个子View的位置
	    leftMenu.layout(-leftMenu.getMeasuredWidth(), 0, 0, b);
	    //第二个子View的位置
	    mainView.layout(l, t, r, b);
	}

Touch events (important) 5. Slide the process

Scroll to the static View seen, the screen is moving
scrollBy (x, y): in the original position on the basis of the scroll (x, y)
the scrollTo (x, y): Scroll to (x, y) position

  @Override
  public boolean onTouchEvent(MotionEvent event) {

      switch (event.getAction()) {
          case MotionEvent.ACTION_DOWN:
              downX = event.getX();//按下时X坐标
              break;
          case MotionEvent.ACTION_MOVE:
              moveX = event.getX();//
              int x_change = (int) (downX - moveX);//x变化(偏移量)
              //当前要滚动的位置 = 之前滚动到的位置 + 偏移量
              curScrollPosition = getScrollX() + x_change;//最新滚动位置
              /**
               *   考虑边界问题
               */
              if (curScrollPosition > 0) {
                  scrollTo(0, 0);
              } else if (curScrollPosition < -leftMenu.getMeasuredWidth()) {
                  scrollTo(-leftMenu.getMeasuredWidth(), 0);
              } else {
                  scrollBy(x_change, 0);//(在范围内)滚动到当前位置
              }
              downX = moveX;//重要点
              break;
          case MotionEvent.ACTION_UP:
              int menu_center = (int) (-leftMenu.getMeasuredWidth() / 2.0f);
              if (getScrollX() < menu_center) {
                  cur_state = MENU_STATE;
              } else {
                  cur_state = MAIN_STATE;
              }
              updateView(cur_state);
              break;
      }
      return true;//一定改成true(消费事件)
  }

When finally let go, we need to let View the Drawer in the open or closed state

    //滑动过程中松开手
    private void updateView(int cur_state) {
        int startX = getScrollX();//负数(当前滑动到的位置)
        int dx = 0;//将要移动的偏移量
        if (cur_state == MAIN_STATE) {//关闭
            dx = 0 - startX;
        } else {
            dx = -leftMenu.getMeasuredWidth() - startX;
        }
        int duration = Math.abs(dx * 2);//动画执行时间可以自行设置
        //Android自带的滚动器执行动画
        scroller.startScroll(startX, 0, dx, 0, duration);
        invalidate();//重绘界面:drawChild--computeScroll()
    }

    //维持动画
    @Override
    public void computeScroll() {
        if (scroller.computeScrollOffset()) {//true动画没结束时(duration时间内)一直调用
            int currX = scroller.getCurrX();//获取当前的模拟值,要滚动的位置
            scrollTo(currX, 0);
            invalidate();//重绘->drawChild--computeScroll()
        }
    }

6. Event conflict

Since Drawer is a ScrollView, sliding events will slide up and down and left and right conflict, this time the need to intercept the event delivery process, to their OnTouchEvent (), otherwise continue to pass child View deal

    @Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                downX = event.getX();
                downY = event.getY();
                break;
            case MotionEvent.ACTION_MOVE:
                //根据偏移量判断是否拦截
                float offsetX = Math.abs(event.getX() - downX);
                float offsetY = Math.abs(event.getY() - downY);
                //当左右滑动偏移量大于上下滑动偏移量,且偏移量大于5时(),进行拦截处理
                if (offsetX > offsetY && offsetX > 5) {
                    return true;//拦截触摸事件,不往里传递,交个自己的OnTouchEvent处理
                }
                break;
            case MotionEvent.ACTION_UP:
                break;
        }
        return super.onInterceptTouchEvent(event);//默认返回false不拦截
    }

7. Program Entry

public class MainActivity extends AppCompatActivity{
    
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        final SlideMenu slideMenu = findViewById(R.id.sm);
        ImageButton imageButton= findViewById(R.id.main_back);
        imageButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                if (v.getId()==R.id.main_back){
	                 //手动设置开关菜单栏
	                 slideMenu.switcheDrawer();
                }
            }
        });
    }
}

Welcome Gangster criticism!

Published 28 original articles · won praise 1 · views 528

Guess you like

Origin blog.csdn.net/qq_40575302/article/details/104533855