• 他们控制的定义:滑动菜单



    滑动面板张女士现在easy找到一个成熟的第三方框架,但是,我们自己做的事,写一些核心代码,帮助我们理解


    1,简单的介绍

    写一个类继承ViewGroup

    复写下面三个方法

    onMeasure -> onLayout -> onDraw

    1。測量左面板和主面板

    左面板宽是指定的值240, 高度是屏幕高度

    主面板宽高就是屏幕的宽高

    2,摆放两个子控件


    左面板的位置: 当前屏幕左边界0, 往左-240

    主面板位置 : 当前控件的位置

    3。处理触摸事件 (左右移动两个控件)


    按下时, 获取按下的坐标downX = 20

    移动时,
    获取当前最新x坐标 moveX = 30
    计算要运行的偏移量 - (30 - 20) = -10
    让偏移生效scrollBy(-10, 0)
    moveX 赋值给 downX, 作为新的按下点
    抬起时, 依据当前偏移位置, 运行动画 (运行平滑动画)


    二,核心代码


    /**
     * 側滑面板
     * @author poplar
     *
     */
    public class SlideMenu extends ViewGroup {
    
    	
    	private final int MAIN_CONTENT = 0; // 主面板状态
    	private final int MENU_CONTENT = 1; // 左菜单状态
    	
    	int currentState = MAIN_CONTENT; // 当前状态
    
    	private Scroller scroller;
    
    	private int downX; // 按下的X值坐标
    	private int downY; // 按下的Y值坐标
    
    	public SlideMenu(Context context) {
    		super(context);
    		init();
    	}
    
    	public SlideMenu(Context context, AttributeSet attrs) {
    		super(context, attrs);
    		init();
    	}
    
    	public SlideMenu(Context context, AttributeSet attrs, int defStyle) {
    		super(context, attrs, defStyle);
    		init();
    	}
    	
    
    	private void init() {
    		// 滚动模拟器
    		
    		scroller = new Scroller(getContext());
    		
    		// startX, x轴从什么位置開始滚动   -100
    		// startY, y轴从什么位置開始滚动
    		// dx, 	   从開始位置 到 目标位置的 偏移量 -100 -> 50  
    				// 偏移量  150  = (50 - (-100))
    				// 偏移量  = (目标位置 x) - (開始位置x)
    		// dy,  
    		// duration , 动画运行时长 dx * 10
    		
    //		scroller.startScroll(startX, startY, dx, dy, duration);
    	}
    
    	/**
    	 * 測量子控件
    	 * widthMeasureSpec : 当前控件的宽度属性
    	 * heightMeasureSpec : 当前控件的高度属性
    	 */
    	@Override
    	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
    		
    		// 获取到左面板
    		View leftMenu = getChildAt(0);
    		// 宽度自身宽度, 高度屏幕的高度
    		leftMenu.measure(leftMenu.getLayoutParams().width, heightMeasureSpec);
    		
    		// 測量主面板
    		View main = getChildAt(1);
    		main.measure(widthMeasureSpec, heightMeasureSpec);
    		
    	}
    
    	/**
    	 * 摆放两个子控件
    	 * 
    	 * left 控件左边界位置
    	 * top  控件上边界位置
    	 * right 控件右边界位置
    	 * bottom 控件下边界位置
    	 * 
    	 */
    	@Override
    	protected void onLayout(boolean changed, int l, int t, int r, int b) {
    
    		// 摆放左面板
    		View leftMenu = getChildAt(0);
    		leftMenu.layout(0 - leftMenu.getMeasuredWidth(), 0, 0, b);
    		
    		// 摆放主面板
    		View main = getChildAt(1);
    		main.layout(l, t, r, b);
    		
    	}
    	
    	@Override
    	public boolean onTouchEvent(MotionEvent event) {
    		switch (event.getAction()) {
    		case MotionEvent.ACTION_DOWN:
    			// 按下时的x坐标
    			downX = (int) event.getX();
    
    			break;
    		case MotionEvent.ACTION_MOVE:
    			// 移动后的x坐标
    			int moveX = (int) event.getX();
    			
    			// 变化量
    			int scrollX = - (moveX - downX);
    			
    			// ------------------------------------------------- 重点 ↓  
    			
    			// 计算变化后的位置
    			int newScrollX = getScrollX() + scrollX;
    			int leftLimit = -getChildAt(0).getMeasuredWidth();
    			if(newScrollX < leftLimit){
    				// < -240
    				scrollTo(leftLimit, 0);
    			} else if (newScrollX > 0) {
    				// >0 限定右边界
    				scrollTo(0, 0);
    			} else {
    				// 让变化量生效
    				scrollBy(scrollX, 0);
    			}
    			
    			// ------------------------------------------------- 以上 ↑
    			
    			//把上一个moveX赋值给downX
    			downX = moveX;
    			
    			break;
    		case MotionEvent.ACTION_UP:
    			// 抬起时, 依据当前偏移位置, 运行动画
    			int leftMenuCenter = - getChildAt(0).getMeasuredWidth() / 2;
    			
    			int currentScrollX = getScrollX();
    			System.out.println("currentScrollX: " + currentScrollX);
    			System.out.println("leftMenuCenter: " + leftMenuCenter);
    			
    			
    			if(currentScrollX > leftMenuCenter){
    				// 假设当前滚动的位置在一半的右边 , 显示主面板 , scrollX > leftMenuCenter
    				currentState = MAIN_CONTENT;
    				System.out.println("运行显示主面板动画");
    				updateCurrentContent();
    			}else {
    				// 假设当前滚动的位置在一半的左边 , 显示左菜单 , scrollX <= leftMenuCenter
    				currentState = MENU_CONTENT;
    				System.out.println("运行显示左菜单动画");
    				updateCurrentContent();
    			}
    			break;
    
    		default:
    			break;
    		}
    		
    		
    		return true;
    	}
    
    	private void updateCurrentContent() {
    		int scrollX = getScrollX();
    		
    		int dx = 0;
    		if(currentState == MAIN_CONTENT){
    			// 运行动画,显示主面板
    //			scrollTo(0, 0);
    			
    			// 目标值 - 当前值
    			dx = 0 - scrollX;
    			
    		} else if(currentState == MENU_CONTENT){
    			// 运行动画,显示左菜单
    //			scrollTo(- getChildAt(0).getMeasuredWidth(), 0);
    			
    			// 目标值 - 当前值
    			// - 240 - 
    			dx = -getChildAt(0).getMeasuredWidth() - scrollX;
    			System.out.println("dx: " + dx + " scrollX: " + scrollX);
    		}
    		
    		// ------------------------------------------------- 重点 ↓  
    
    		// 開始模拟数据
    		scroller.startScroll(scrollX, 0, dx, 0, Math.abs(dx * 10));
    		// -100 -> -240   >>  -150
    		
    		// 使scroller模拟的数据生效
    		invalidate(); // drawChild -> child.draw( ->  computeScroll
    
    		// ------------------------------------------------- 以上 ↑
    		
    	}
    	// ------------------------------------------------- 重点 ↓  
    
    	@Override
    	public void computeScroll() {
    		
    		if(scroller.computeScrollOffset()){
    			// 动画还没运行完
    			
    			// 得到当前模拟的数值
    			int currX = scroller.getCurrX();
    			scrollTo(currX, 0);
    //			System.out.println("currX: " + currX);
    			
    			// 重绘界面, 递归调用
    			invalidate();
    		}
    	}
    
    	// ------------------------------------------------- 以上 ↑
    	
    	@Override
    	public boolean onInterceptTouchEvent(MotionEvent ev) {
    		// 仅仅有在用户水平滑动的时候才拦截
    		switch (ev.getAction()) {
    			case MotionEvent.ACTION_DOWN:
    				downX = (int) ev.getX();
    				downY = (int) ev.getY();
    				
    				break;
    			case MotionEvent.ACTION_MOVE:
    				int moveX = (int) ev.getX();
    				int moveY = (int) ev.getY();
    				
    				int diffX = Math.abs(moveX - downX);
    				int diffY = Math.abs(moveY - downY);
    				
    				if(diffX > diffY && diffX > 10){
    					return true;
    				}
    				break;
    			case MotionEvent.ACTION_UP:
    				
    				break;
    	
    			default:
    				break;
    		}
    		
    		return super.onInterceptTouchEvent(ev);
    	}
    }
    





    版权声明:本文博主原创文章,博客,未经同意不得转载。

  • 相关阅读:
    添加AdMob的Native广告
    androidx.recyclerview.widget.RecyclerView的使用方法
    androidx.recyclerview.widget.RecyclerView 使用记录
    ViewPager使用
    小程序加载云端数据库中的第二页数据,前端如何动态显示?
    小程序页面跳转传递参数
    小程序云端函数 where遇到的问题
    Python 加载包含多个JSON对象的JSON文件
    如何把一个目录下的中文名字的文件全部变成拼音命名的文件?
    小技巧--解决eclipse导入的jar文件后,无法使用默认包中的方法问题
  • 原文地址:https://www.cnblogs.com/bhlsheji/p/4917193.html
Copyright © 2020-2023  润新知