V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
karonl
V2EX  ›  Android

开源 Android InDoorView 室内选位控件,助力快速开发

  •  
  •   karonl · 2016-06-26 00:10:56 +08:00 · 10258 次点击
    这是一个创建于 3071 天前的主题,其中的信息可能已经有所发展或是发生改变。

    介绍

    先给个简单的介绍,最近接到个 case ,大概是开发一个可以室内选工位的 app 。这我们很容易想到电影院的选座位,可有点不一样,因为每个区域都是不同大小并且位置不一,而我们手上的材料只有一张标识有区域的 jpg 地图。一开始我使用引擎来做,结果可想而知,为了个简单功能引入整个库非常不明智。

    应用场景:

    该控件可让室内图片上的区域拥有点击事件,可用于开发电影院选座、商场购物地图、展位摊位在线预定、办公场地租赁工位等需要操作不规则区域的功能。

    示例图

    原理:

    把读取地图底图 bitmap 和使用 Paint 的钢笔路径集合一同绘制到一个 canvas 上保存,并通过继承 SurfaceView 把 canvas 绘制到双缓画布中,通过 canvas.drawBitmap 实现缩放和移动,重写 view 点击事件结合 Region 判断点击坐标位于哪个区域内,再通过接口反馈事件。

    采用把所有图案内容事先缓存到 canvas 的方法,使用非 UI 线程进行绘制,可实现每秒 60 次左右的界面绘制,实现流畅的移动和缩放操作;在没交互情况下,暂停绘制及刷新以节约计算资源。

    特性:

    1. 性能较强,绘制达到 60 帧上下
    2. 支持缩放以及拖动
    3. 直接使用原生 SurfaceView ,无需导入庞大的引擎库

    Github:

    https://github.com/karonl/InDoorSurfaceView (thanks for your star✨)

    Demo:

    直接使用 Android Studio 导入工程即可运行

    如何导入 InDoorView 库:

    1. clone 到本地
    2. 复制 InDoorView 文件夹到目标项目的根目录 (InDoorView 使用的是 apply plugin: 'com.android.library')
    3. 在 settings.gradle 文件中 include ':InDoorView'
    4. 在主模块(一般是 app 文件夹)中的 build.gradle 中添加依赖
      dependencies {
         compile project(':InDoorView')
      }
      
    5. 点击 Sync 进行构建
    6. 根目录的 src 是 demo ,可做参考

    注:直接导入工程是 demo ,可直接运行测试

    如何使用:

    1. 初始化 在 xml 文件中使用进行声明

      <com.karonl.instance.InDoorView
          android:id="@+id/surface"
          android:layout_width="match_parent"
          android:layout_height="match_parent" />
      

      在对应的 activity 中进行引用,并通过设置适配器,把底图和区域 list 填入,并 refreshData();

      InDoorSurfaceView view = (InDoorSurfaceView)findViewById(R.id.surface);
      DataAdapter adapter =  new DataAdapter();
      view.setAdapter(adapter);//初始化
      adapter.setBmp(bmp);//设置图片(底图)
      adapter.setList(list);//设置数组(图上的可点区域)
      adapter.refreshData();
      
    2. 上面代码的 list 的具体设置看这里:

      (输入钢笔路径相对于图片左上角的节点坐标)

      //每个图案的节点坐标集合
      private List<PointF> getList(){
          float density = getResources().getDisplayMetrics().density;
          List<PointF> pointList = new ArrayList<>();
          pointList.add(new PointF(99.1f * density,673.1f * density));
          pointList.add(new PointF(222.1f * density,670.1f * density));
          pointList.add(new PointF(227.1f * density,327.1f * density));
          pointList.add(new PointF(94.1f * density,321.1f * density));
          pointList.add(new PointF(100.1f * density,674.1f * density));
          return pointList;
      }
      
      //区域列表
      private void getUnitList(){
          PathUnit unit = new PathUnit(getList());//把节点换成一个 PathUnit 元素
          unit.setName("John Market");//设置元素的名字
          unitList.add(unit);//添加到区域列表
      }
      
      

      注:从资源读取的图片对应的坐标要乘上 desity ,网络加载的图片则不用

    3. 接口说明: 通过该接口可以返回点击到的区域的 PathUnit 元素,可通过此来获取区域名字等信息

      view.setOnClickMapListener(new InDoorSurfaceView.onClickMapListener() {
          @Override
          public void onClick(PathUnit region) {
          //读取 pathunit
          }
      }            
      

      该接口是 fps 帧率

      view.onFramesListener(new InDoorSurfaceView.FramesListener() {
          @Override
          public void onRefresh(float number) {
          //帧率
          }
      }    
      

    环境:

    compileSdkVersion 24
    buildToolsVersion "24.0.0"
    minSdkVersion 16
    gradle plugin:gradle:2.1.2
    

    另外:

    1. 如果你有项目使用了该库也可以告知我,我将把你的 app 作为示例
    2. 如果你有建议或者想法,也欢迎告知我,这将让开源代码变得更好
    3. 如果程序有 bug 和改善方法,感谢提 Issues ,有劳指教!
    第 1 条附言  ·  2016-06-26 02:05:19 +08:00
    为每个区域分别设定坐标的时候,衡量 x , y 确实繁琐。不过已经为此开发了个前端版本的 “绘制画板”,事先导入图片,通过圈选出所有区域,最后生成 json 。当然你也可以自己写个协助程序,或者等我开源。
    6 条回复    2016-06-26 15:24:44 +08:00
    kenshinhu
        1
    kenshinhu  
       2016-06-26 00:21:57 +08:00
    这个之前也有尝试过用 svg 来实现,但代价是需求美工将图用 AI 来绘,之后手动在对应的区域映射指定的事件
    xiezuan
        2
    xiezuan  
       2016-06-26 00:30:44 +08:00 via iPhone
    好牛,看下
    Ervin
        3
    Ervin  
       2016-06-26 03:32:26 +08:00 via Android
    666666
    kslr
        4
    kslr  
       2016-06-26 06:13:25 +08:00 via Android
    Nice
    sobigfish
        5
    sobigfish  
       2016-06-26 15:18:03 +08:00
    SVG+JSON 的数据源更方便点吧。。。
    区块有 ID , json 直接对应 ID
    karonl
        6
    karonl  
    OP
       2016-06-26 15:24:44 +08:00
    @sobigfish 这个提议可以,回头研究一下
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   978 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 25ms · UTC 20:56 · PVG 04:56 · LAX 12:56 · JFK 15:56
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.