车载设置--音场设置 自定义跟随手指移动的小球

需求分析
这车载设置中,一般都会有音场设置,效果图如下:
这里写图片描述
就是要实现让如图所示的小球在指定区域内跟随手指移动,同时左边的数值跟随变化。当拖动左边的进度条时,小球也跟随变化,这里不做讲解,主要实现小球跟随手指的移动而移动。

案例实现
1.由于小球是在指定区域内移动,首先我们就需要获取指定区域的宽高,而需要获取控件的宽高,在 onCreate 是获取不到的,因为 View 组件布局要在 onResume 回调后完成,通常的做法是使用 getViewTreeObserver().addOnGlobalLayoutListener() 来获得宽度或者高度。OnGlobalLayoutListener 是 ViewTreeObserver 的内部类,当一个视图树的布局发生改变时,可以被 ViewTreeObserver 监听到,这是一个注册监听视图树的观察者 (observer),在视图树的全局事件改变时得到通知。ViewTreeObserver 不能直接实例化,而是通过 getViewTreeObserver() 获得。同时需要注意的是 OnGlobalLayoutListener 可能会被多次触发,因此在得到了高度之后,要将 OnGlobalLayoutListener 注销掉。代码如下:

 mBallZone.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
            @Override
            public void onGlobalLayout() {
                mBallZone.getViewTreeObserver().removeOnGlobalLayoutListener(this);
                mZoneHeight = mBallZone.getMeasuredHeight();
                mZoneWidth = mBallZone.getMeasuredWidth();
                Log.d(TAG, "onGlobalLayout: "+mZoneHeight+".."+mZoneWidth);
                mPointX = mZoneWidth/2;
                mPointY = mZoneHeight /2;

            }
        });

2.小球的移动范围是有边界控制的,小球离边界的距离相差一个半径,所以我们需要获取小球半径:

 private void getImageOps(){
        mSrcBitmap = BitmapFactory.decodeResource(getResources(),
                R.drawable.setting_balance_centre);
        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeResource(getResources(), R.drawable.setting_balance_centre, opts);
        opts.inSampleSize = 1;
        opts.inJustDecodeBounds = false;
        Bitmap mBitmap =BitmapFactory.decodeResource(getResources(), R.drawable.setting_balance_centre, opts);
        mBallWidth =opts.outWidth;
        mBallHeight =opts.outHeight;
    }

3.获取到了指定移动范围和小球的半径参数后,接下来就是对手势监听,使得小球跟随手指移动。

    class DrawBall extends View {

        public DrawBall(Context context) {
            super(context);
        }

        public DrawBall(Context context, AttributeSet attrs) {
            super(context, attrs);
        }

        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap(mSrcBitmap,mPointX-mBallWidth/2, mPointY-mBallHeight/2, null);
            Log.d(TAG, "onDraw: mPointX::"+mPointX+"...mPointY::"+mPointY);
            mIvHor.setY(mPointY);
            mIvVer.setX(mPointX);

        }

        @Override
        public boolean onTouchEvent(MotionEvent event) {
//            mIsTouchBall = true;
            mPointX = event.getX();
            mPointY = event.getY();
            isInvalidPoint();
            mBall.invalidate();
            return true;
        }

    }

    /**
     * 做边界判断,超过边界范围的,都默认等于边界值
     */
    private void isInvalidPoint(){
        if (mPointX-mBallWidth/2 <= 0)
            mPointX = mBallWidth/2;
        if (mPointY -mBallHeight/2<= 0)
            mPointY = mBallHeight/2;
        if (mPointX +mBallWidth/2>= mZoneWidth)
            mPointX = mZoneWidth-mBallWidth/2;
        if (mPointY +mBallHeight/2>= mZoneHeight)
            mPointY = mZoneHeight-mBallHeight/2;
    }

在代码中,将当前 onTouchEvent 方法返回 ture,表明这个 view 是要对当前手势操作进行捕获的,同时调用 mBall.invalidate() 刷新界面。

4.水平线与垂直线跟随手指的移动,当小球重绘时,同时改变两根线的位置。

 @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            canvas.drawBitmap(mSrcBitmap,mPointX-mBallWidth/2, mPointY-mBallHeight/2, null);
            Log.d(TAG, "onDraw: mPointX::"+mPointX+"...mPointY::"+mPointY);
            mIvHor.setY(mPointY);
            mIvVer.setX(mPointX);

        }

5.使用方法
在 onCreate 中,创建自定义的小球 mBall,并将这个自定义的控件加入到父布局中:

 mBall = new DrawBall(this);
mBallZone.addView(mBall);

这里列出的代码差不多都是伪代码,在实际使用中可能还需要调试,因为涉及到公司利益,就不贴全部代码,但相信,上述代码,基本能实现小球跟随手指移动而移动的功能了!


happy a nice day!

猜你喜欢

转载自blog.csdn.net/liqianwei1230/article/details/78336819
今日推荐