图片上画瞄点点击需求

  • 需求

最近有一个需求是做类似百度地图那样子的点击图片的某个地方然后有相应的响应。

其实这种需求的话如果是3D的话,android如果最好的话可以使用游戏框架,或者前端的一些three.js等一些有元素绑定的框架来做那么就简单好多了,因为你所点击的某个地方是一个元素,它可以附带各种事件。
2D的话或者可以用svg图 然后解析对应的节点给每个节点做一些点击事件的处理,很多svg地图也是这样子做的,有兴趣大家可以百度一下。

这里呢,用了安卓源生最最最简单 不过也是最不可取的方法啦,不过自己没做事写了一下类似的东西,就记录一下吧~~~


效果图先看为敬.gif

大家看一下这种效果,就是加载一张图片,并且图片上方画上图形,然后给个上面画上一些圆点,然后点击做相应的操作。

下面说一下这个实现的过程吧,以及需要注意的一些点~~

  • 先用画笔在ImageView上面画出对应的圆心,确定可点击的范围。
  • 给个开关,开启的时候,圆点可以移动,关闭的时候圆点不可移动。
    注意点
  • 如果圆点被移除布局外,要重新在布局中画出来这个点,不然这个点就不见了。
  • 要保持一时间只有一个点的响应点击移动事件,不然两个点或多个点一旦重合在一起就出现移动不出来,看起来是一个点实际上是两个点或者多个点。

相关的知识点无非就是onDraw()方法的先后绘画顺序,已经点击事件的一点分发知识点。或许还有一些绘画的paint、点击事件的坐标跟屏幕的坐标~ (很基础的)

  1. 为小圆点定义的实体类
open class BasePointBean : Serializable {
    var id: Int = 0        //点的id
    var name: String? = null  //点的名字
    var isTouch: Boolean = false  //是否被点击
    //圆心
    var x: Double = 0.0  
    var y: Double = 0.0 
}
/**
 * Create by ldr
 * on 2019/10/29 14:01.
 * 用于存储图片上的点
 */
class OperationRoomBean : BasePointBean() {
  //可点击的范围
    var region: Region? = null
        get() = Region((x - 40).toInt(), (y - 40).toInt(), (x + 40).toInt(), (y + 40).toInt())
//圆点的外围画笔
    var paintOut: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
//圆心的内围画笔
    var paintIn: Paint = Paint(Paint.ANTI_ALIAS_FLAG)
    init {
        paintOut.color = Color.parseColor("#FFFFFF")
        paintIn.color = Color.parseColor("#A5DCE9")
    }
    fun setIsTouch(select: Boolean) {
        isTouch = select
        if (select) {
            paintOut.color = Color.parseColor("#DDD0D0")
            paintIn.color = Color.parseColor("#5AD5E4")
        } else {
            paintOut.color = Color.parseColor("#FFFFFF")
            paintIn.color = Color.parseColor("#A5DCE9")
        }
    }
    companion object {
        val TAG = "OperationRoomBean"
    }
}
  1. 自定义CustomPic继承ImageView重写一下绘画相关的方法跟点击事件相应的方法

class CustomPic : ImageView {
    companion object {
        val TAG = "CustomPic"
    }

    //switch控件开关值,可不可以移动
    var isChangLocal: Boolean = false
    //获取该布局的矩形,作用:用于判断圆点是不是在布局中,不在要重新绘制
    var globalLocalRect = Rect()
    //在某一些坐标上面画点
    var arrayOperationRoomBean = ArrayList<OperationRoomBean>()


    constructor(context: Context) : super(context) {
    }
    constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) {
    }
    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
        context,
        attrs,
        defStyleAttr
    ) {
    }
  //传入点的时候 调用重新刷一下页面
    fun setData(arrayOperationRoomBean: ArrayList<OperationRoomBean>){
      this.arrayOperationRoomBean = arrayOperationRoomBean
        invalidate()
    }

    fun getData():ArrayList<OperationRoomBean>{
        return arrayOperationRoomBean
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)
    }
    override fun dispatchDraw(canvas: Canvas?) {
        super.dispatchDraw(canvas)
        // 获取该Pic的可见范围

        this.getLocalVisibleRect(globalLocalRect)
         for (oper in arrayOperationRoomBean) {
            drawCirCle(oper, canvas!!,globalLocalRect)
        }
    }

    /**
     * 画圆点 用于显示出要点击的点
     * @param operationRoomBean 圆点的数据
     * @param canvas 当前的画布
     * @param rect 当前的这个CustomPic的可视范围 相对于
     *
     * 三点步骤:
     * 第一点 先判断 operationRoomBean圆点的数据的x y ,如果不在getLocalVisibleRect的范围内就改变x,y,使其在getLocalVisibleRect的范围内
     * 第二点 根据点画改点的可以点击范围
     * 第三点 开始画圆的外圈跟圆的内圈
     * 有关键一点需要注意: drawCircle的x跟y相对于当前父控件的canvas
     */
    fun drawCirCle(operationRoomBean: OperationRoomBean, canvas: Canvas,rect: Rect) {
        operationRoomBean.let {
            //这里是防止被拉到不可见区域的时候 导致数据不可见
            if (!rect.contains((it.x).toInt(), it.y.toInt())) {
                it.x = 40.0
                it.y = 40.0
                it.region = Region(
                    (it.x - 40).toInt(),
                    (it.y - 40).toInt(),
                    (it.x + 40).toInt(),
                    (it.y + 40).toInt()
                )
            }
            canvas?.drawCircle(it.x.toFloat(), it.y.toFloat(), 20f, it.paintOut)
            canvas?.drawCircle(it.x.toFloat(), it.y.toFloat(), 10f, it.paintIn)
        }
    }
  
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        var onOneBeSelect = true //这个节点是为了防止两个多个点在附近会同时被点击进而变成一个点
        when (event!!.action) {
            MotionEvent.ACTION_DOWN -> {
                Log.i(TAG, "MotionEvent.ACTION_DOWN")
                for (operationRoomBean in arrayOperationRoomBean) {
                    //没有点击到它 则将它的属性设置为没有被点击
                    if (!operationRoomBean.region!!.contains(event.x.toInt(), event.y.toInt())){
                        operationRoomBean.setIsTouch(false)
                        continue
                    }
                    //已经有其他点被选中了 则当前的属性也给改成没有被点击
                    if(!onOneBeSelect){
                        operationRoomBean.setIsTouch(false)
                        continue
                    }
                    onOneBeSelect = false
                    operationRoomBean.setIsTouch(true)
                    if (isChangLocal) {//这个节点判断是不是用于移动
                        Toast.makeText(context, "当前点击${operationRoomBean.name}", Toast.LENGTH_SHORT).show()
                    } else {
                        Toast.makeText(context, "当前点击${operationRoomBean.name},不可移动", Toast.LENGTH_SHORT).show()
                    }
                }
                invalidate()
            }
            MotionEvent.ACTION_MOVE -> {
                Log.i(TAG, "MotionEvent.ACTION_MOVE")
                if (isChangLocal) {
                    for (operationRoomBean in arrayOperationRoomBean) {
                        if (!operationRoomBean.region!!.contains(event.x.toInt(), event.y.toInt())){
                            continue
                        }
                        if (!operationRoomBean.isTouch){
                            continue
                        }
                        // 将移动的坐标存入给圆点的实体operationRoomBean,并设置可点击区域 最后刷新页面
                        operationRoomBean.apply {
                                Log.i(TAG, "MotionEvent.ACTION_MOVE")
                                x = event.x.toDouble()
                                y = event.y.toDouble()
                                region = Region(
                                    (x - 40).toInt(),
                                    (y - 40).toInt(),
                                    (x + 40).toInt(),
                                    (y + 40).toInt()
                                )
                                invalidate()
                        }
                    }
                }
            }
            MotionEvent.ACTION_UP -> {
                Log.i(TAG, "MotionEvent.ACTION_UP")
                onOneBeSelect = true
            }
        }
        return true
    }


    //切换横竖屏操作
    fun isScreenOriatationLandscape(context: Context): Boolean {
        return context.resources.configuration.orientation == Configuration.ORIENTATION_LANDSCAPE
    }



}

主要是上面这CustomPic做一些点击事件的一些处理,再调用invalidate()去刷新页面。(必要的注释都在上面的类中了)

ps:这个方案不适合多种机型,只适合在单独的机型上面或者在调试前可以先配置信息的机型上面,实际使用的时候不让用户移动点 直接固定在那里。

你可以将点的信息存储到本地,那么下次打开软件加载点的信息就可以直接用了,上面提供的类可以直接copy到本地使用,但是传入的数据要自己构造一下传入。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,736评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,167评论 1 291
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,442评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,902评论 0 204
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,302评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,573评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,847评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,562评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,260评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,531评论 2 245
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,021评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,367评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,016评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,068评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,827评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,610评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,514评论 2 269

推荐阅读更多精彩内容