Android自定义View实现遥控器按钮

本文实例为大家分享了Android自定义View实现遥控器按钮的具体代码,供大家参考,具体内容如下

效果图:

原理:

  • onSizeChanged拿到控件宽高,进行path和region的计算(此处,path和region的坐标值都是以viewWidth/2,viewHeight/2为坐标原点进行计算的)
  • 画布平移,绘制5个path
  • 点击事件,判断是否处于相应的region区域内,进行控件的重绘
  • 点击事件motionEvent的原始坐标(getX和getY),是以viewParent的左上角为坐标原点的,需要经过matrix转换成以控件中心点为原点的坐标体系。

Region区域,paint的style设置为stroke模式,遍历绘制

mPaint.setColor(Color.RED);
RegionIterator iterator = new RegionIterator(topRegion);
 Rect r = new Rect();
 while (iterator.next(r)) {
      canvas.drawRect(r, mPaint);
 }

源码:

public class RemoteControlMenu extends View {

    private int mWidth;
    private int mHeight;

    private RectF bigRectF;
    private int bigRadius;
    private RectF smallRectF;
    private int smallRadius;
    private int padding = 20;
    private int sweepAngel = 80;
    private int offsetAngel;

    @TouchArea
    private int mTouchArea = TouchArea.INVALID;

    private Paint mPaint;
    private Region topRegion, bottomRegion, leftRegion, rightRegion, centerRegion, globalRegion;
    private Path topPath, bottomPath, leftPath, rightPath, centerPath, selectedPath;

    Matrix mMapMatrix;

    private int unselectedColor = 0xff4c5165;
    private int selectedColor = 0xffdd9181;

    private boolean isSelected = false;

    public RemoteControlMenu(Context context) {
        this(context, null);
    }

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs, 0);
    }

    public RemoteControlMenu(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        mPaint = new Paint();
        mPaint.setAntiAlias(true);
        mPaint.setStyle(Paint.Style.FILL);
        mPaint.setStrokeWidth(4);
        mPaint.setColor(unselectedColor);

        offsetAngel = (360 - sweepAngel * 4) / 4;
        bigRectF = new RectF();
        smallRectF = new RectF();

        topRegion = new Region();
        bottomRegion = new Region();
        leftRegion = new Region();
        rightRegion = new Region();
        centerRegion = new Region();
        globalRegion = new Region();
        topPath = new Path();
        bottomPath = new Path();
        leftPath = new Path();
        rightPath = new Path();
        centerPath = new Path();
        mMapMatrix = new Matrix();
    }

    @Retention(RetentionPolicy.SOURCE)
    @IntDef({TouchArea.LEFT, TouchArea.TOP, TouchArea.RIGHT, TouchArea.BOTTOM,
            TouchArea.CENTER, TouchArea.INVALID})
    private @interface TouchArea {
        int LEFT = 1;
        int TOP = 2;
        int RIGHT = 3;
        int BOTTOM = 4;
        int CENTER = 5;
        int INVALID = 0;
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        float[] pts = new float[2];
        pts[0] = event.getX();
        pts[1] = event.getY();
        Log.d("zhen", "原始触摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix);
        mMapMatrix.mapPoints(pts);

        int x = (int) pts[0];
        int y = (int) pts[1];
        Log.w("zhen", "转换后的触摸位置:" + Arrays.toString(pts) + " mMapMatrix: " + mMapMatrix);
        int touchArea = TouchArea.INVALID;
        switch (event.getAction()) {
            case MotionEvent.ACTION_UP:
                if (leftRegion.contains(x, y)) {
                    touchArea = TouchArea.LEFT;
                }
                if (topRegion.contains(x, y)) {
                    touchArea = TouchArea.TOP;
                }
                if (rightRegion.contains(x, y)) {
                    touchArea = TouchArea.RIGHT;
                }
                if (bottomRegion.contains(x, y)) {
                    touchArea = TouchArea.BOTTOM;
                }
                if (centerRegion.contains(x, y)) {
                    touchArea = TouchArea.CENTER;
                }
                if (touchArea == TouchArea.INVALID) {
                    mTouchArea = touchArea;
                    Log.w("zhen", "点击outside");
                } else {
                    if (mTouchArea == touchArea) {
                        //取消选中
                        isSelected = false;
                        mTouchArea = TouchArea.INVALID;
                    } else {
                        //选中
                        isSelected = true;
                        mTouchArea = touchArea;
                    }
                    Log.w("zhen", "按钮状态 mTouchArea " + mTouchArea + " isSelected: " + isSelected);
                    if (mListener != null) {
                        mListener.onMenuClicked(mTouchArea, isSelected);
                    }
                    invalidate();
                }
                break;
        }

        return true;
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        mWidth = w;
        mHeight = h;
        //大圆
        bigRadius = (Math.min(mWidth, mHeight) - 250) / 2;
        bigRectF.set(-bigRadius, -bigRadius, bigRadius, bigRadius);
        //小圆
        smallRadius = (bigRadius - padding) / 2;
        smallRectF.set(-smallRadius - padding, -smallRadius - padding,
                smallRadius + padding, smallRadius + padding);

        mMapMatrix.reset();
        globalRegion.set(-mWidth / 2, -mHeight / 2, mWidth / 2, mHeight / 2);

        centerPath.addCircle(0, 0, smallRadius, Path.Direction.CW);
        centerRegion.setPath(centerPath, globalRegion);

        float startAngel = -sweepAngel / 2f;
        rightPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        rightPath.arcTo(smallRectF, startAngel, -sweepAngel);
        rightPath.close();
        rightRegion.setPath(rightPath, globalRegion);

        startAngel += offsetAngel;
        bottomPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        bottomPath.arcTo(smallRectF, startAngel, -sweepAngel);
        bottomPath.close();
        bottomRegion.setPath(bottomPath, globalRegion);

        startAngel += offsetAngel;
        leftPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        leftPath.arcTo(smallRectF, startAngel, -sweepAngel);
        leftPath.close();
        leftRegion.setPath(leftPath, globalRegion);

        startAngel += offsetAngel;
        topPath.addArc(bigRectF, startAngel, sweepAngel + 4);
        startAngel += sweepAngel;
        topPath.arcTo(smallRectF, startAngel, -sweepAngel);
        topPath.close();
        topRegion.setPath(topPath, globalRegion);
        Log.d("zhen", "globalRegion: " + globalRegion);
        Log.d("zhen", "globalRegion: " + globalRegion);
        Log.d("zhen", "leftRegion: " + leftRegion);
        Log.d("zhen", "topRegion: " + topRegion);
        Log.d("zhen", "rightRegion: " + rightRegion);
        Log.d("zhen", "bottomRegion: " + bottomRegion);
        Log.d("zhen", "centerRegion: " + centerRegion);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        canvas.translate(mWidth / 2, mHeight / 2);
        // 获取测量矩阵(逆矩阵)
        if (mMapMatrix.isIdentity()) {
            canvas.getMatrix().invert(mMapMatrix);
        }

        mPaint.setColor(unselectedColor);
        canvas.drawPath(centerPath, mPaint);
        canvas.drawPath(rightPath, mPaint);
        canvas.drawPath(bottomPath, mPaint);
        canvas.drawPath(leftPath, mPaint);
        canvas.drawPath(topPath, mPaint);

        if (!isSelected) return;
        mPaint.setColor(selectedColor);
        switch (mTouchArea) {
            case TouchArea.LEFT:
                canvas.drawPath(leftPath, mPaint);
                break;
            case TouchArea.TOP:
                canvas.drawPath(topPath, mPaint);
                break;
            case TouchArea.RIGHT:
                canvas.drawPath(rightPath, mPaint);
                break;
            case TouchArea.BOTTOM:
                canvas.drawPath(bottomPath, mPaint);
                break;
            case TouchArea.CENTER:
                canvas.drawPath(centerPath, mPaint);
                break;
        }
        Log.e("zhen", " touchArea: " + mTouchArea);

        //Android还提供了一个RegionIterator来对Region中的所有矩阵进行迭代,
        // 可以使用该类,获得某个Region的所有矩阵
        //通过遍历region中的矩阵,并绘制出来,来绘制region
//        mPaint.setColor(Color.RED);
//        RegionIterator iterator = new RegionIterator(topRegion);
//        Rect r = new Rect();
//        while (iterator.next(r)) {
//            canvas.drawRect(r, mPaint);
//        }
//
//        mPaint.setColor(Color.BLUE);
//        RegionIterator iterator1 = new RegionIterator(leftRegion);
//        Rect r1 = new Rect();
//        while (iterator1.next(r1)) {
//            canvas.drawRect(r1, mPaint);
//        }
//
//        mPaint.setColor(Color.BLACK);
//        RegionIterator iterator2 = new RegionIterator(rightRegion);
//        Rect r2 = new Rect();
//        while (iterator2.next(r2)) {
//            canvas.drawRect(r2, mPaint);
//        }
//
//        mPaint.setColor(Color.YELLOW);
//        RegionIterator iterator3 = new RegionIterator(bottomRegion);
//        Rect r3 = new Rect();
//        while (iterator3.next(r3)) {
//            canvas.drawRect(r3, mPaint);
//        }
//
//        mPaint.setColor(Color.GREEN);
//        RegionIterator iterator4 = new RegionIterator(centerRegion);
//        Rect r4 = new Rect();
//        while (iterator4.next(r4)) {
//            canvas.drawRect(r4, mPaint);
//        }
    }

    private MenuListener mListener;

    public void setListener(MenuListener listener) {
        mListener = listener;
    }

    // 点击事件监听器
    public interface MenuListener {
        void onMenuClicked(int type, boolean isSelected);
    }
}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我们。

(0)

相关推荐

  • Android按钮美化样式的实现代码

    话不多说,上运行效果图 在drawable文件夹下 新建button_drawable.xml <?xml version="1.0" encoding="utf-8" ?> <!--相当于做了一张圆角的图片,然后给button作为背景图片--> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="

  • Android实现输入法弹出时把布局顶上去和登录按钮顶上去的解决方法

    背景:在写登录界面时,老板就觉得在输入密码的时候谈出来的输入法软键盘把登录按钮遮挡住了(入下图所示,不爽),连输入框都被挡了一半,于是不满意了,要叫我改,于是我看QQ的登录效果,我就去研究了一下,弹出输入法整个布局上来了,终于让老板满意了. (如上图这样,老板不满意的,呵呵) 1,咱们就解决问题吧. 我看了很多博客和问答,很多人都说直接在在AndroidManifest.xml中给这个Activity设置 <activity android:windowSoftInputMode="sta

  • android为ListView每个Item上面的按钮添加事件

    本文介绍了ListView给每个Item上面的按钮添加事件,具体如下: 1.先看下效果图: 在这里仅供测试,我把数据都写死了,根据需要可以自己进行修改,此外实现ListView上面每个Item上的Button的事件有两种方法: 1.使用final变量扩展局部变量的生命周期范围主要代码(本文最后附全部代码): //注意原本getView方法中的int position变量是非final的,现在改为final @Override public View getView(final int posit

  • Android按钮按下的时候改变颜色实现方法

    需求是在我按下按钮时,该变按钮颜色,使用户感觉到自己按了按钮,当松开的时候,变回原来的颜色. 正常时: 按下时: 有人说,直接监听按钮的按下事件不得了嘛,其实这样确实能实现同样的效果,但是有个缺点,比如很多按钮都需要这样的效果,那你同样的代码就要重复很多次.所以,还是要通用起来. 首先,在res文件夹下新建一个文件夹drawable,这是无关分辨率的: 在下面建立一个xml文件:login_button_selector.xml 复制代码 代码如下: <selector xmlns:androi

  • 基于Android实现点击某个按钮让菜单选项从按钮周围指定位置弹出

    Android Material Design:PopupMenu Android Material Design 引入的PopupMenu类似过去的上下文菜单,但是更灵活. 如图所示: 现在给出实现上图PopupMenu的代码. 本例是一个普通的Button触发弹出PopupMenu. 测试的MainActivity.java : package zhangphil.materialdesign; import android.app.Activity; import android.os.B

  • Android中让按钮拥有返回键功能的方法及重写返回键功能

    让按钮拥有返回键的功能很简单,在点击事件加上finish();就OK了. 如: 复制代码 代码如下: public void onClick(View v){ finish(); } finish() 仅仅是把activity从当前的状态退出,但是资源并没有给清理. 其实android的机制决定了用户无法完全退出application,即使用System.exit(). android自己决定何时该从内存中释放程序,当系统没有可用内存时,就会按照一定的优先级来销毁应用程序. android手机操

  • Android单选按钮RadioButton的使用详解

    RadioButton是最普通的UI组件之一,继承了Button类,可以直接使用Button支持的各种属性和方法. RadioButton与普通按钮不同的是,它多了一个可以选中的功能,可额外指定一个android:checked属性,该属性可以指定初始状态时是否被选中,其实也可以不用指定,默认初始状态都不选中. 使用RadioButton必须和单选框RadioGroup一起使用,在RadioGroup中放置RadioButton,通过setOnCheckedChangeListener( )来响

  • Android Studio中Run按钮是灰色的快速解决方法

    首先是,在不同的AS中,gradle版本不同,下载的sdk版本不同,这些,都在gradle(Project.Models)相关代码里调过来就好.之前的文章里有说过. 经过调好gradle这些文件,AS已经可以built 成功后. 下一步,Run the application. 这时候,遇到问题:Run按钮灰色,失效. 点击Run旁边 Select Run/Debug Configuration按钮 选择 Edit Configuration,于是: 在model下拉框中选择app.如果下拉框中

  • Android开发悬浮按钮 Floating ActionButton的实现方法

    一.介绍 这个类是继承自ImageView的,所以对于这个控件我们可以使用ImageView的所有属性 android.support.design.widget.FloatingActionButton 二.使用准备, 在as 的 build.grade文件中写上 compile 'com.android.support:design:22.2.0' 三.使用说明 xml文件中,注意蓝色字体部分 <android.support.design.widget.FloatingActionButt

  • Android按钮单击事件的四种常用写法总结

    很多学习Android程序设计的人都会发现每个人对代码的写法都有不同的偏好,比较明显的就是对控件响应事件的写法的不同.因此本文就把这些写法总结一下,比较下各种写法的优劣,希望对大家灵活地选择编码方式可以有一定的参考借鉴价值. xml文件代码如下: <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_conte

随机推荐