跟着項目學 android canvas——InDoorView 地圖引擎

無依賴第三方庫的室內戶型圖交互組件庫
no-dependency Indoor map view library.java

項目結構

github:github.com/karonl/InDo…(歡迎stars) 該 master branch 爲完整的演示項目,其中 Sample 爲應用模塊,InDoorView 爲庫模塊,LICENSE 爲版權說明。android

快速體驗

  1. 下載apk: http://leanclub.cn/InDoorViewSample.apk
  2. 查看mp4: http://leanclub.cn/Screenrecord20170504.mp4
  3. 示例圖片:
    截圖

應用場景

該控件可以讓室內圖片上的區域擁有點擊事件,可用於開發電影院選座、商場購物地圖、展位攤位在線預約、辦公場地租賃工位等須要操做不規則區域功能。 若是這正是你所須要的,能夠點擊該庫的 Star (thanks for your star✨),便於收藏學習和關注最新動態。git

快速開始

  1. Add it in your root build.gradle at the end of repositories:
allprojects {
  repositories {
    jcenter()
    maven { url 'https://jitpack.io' }
  }
}
複製代碼
  1. 在 app 應用模塊的 build.gradle 引入
dependencies {
  compile 'com.github.karonl:InDoorSurfaceView:1.0'
}
複製代碼
  1. 在 xml 文件中進行組件聲明
<com.karonl.instance.InDoorView android:id="@+id/surface" android:layout_width="match_parent" android:layout_height="match_parent" />
複製代碼
  1. 在對應的 activity 中進行引用,並經過設置適配器,把底圖和區域 list 填入,最後 refreshData();
InDoorView view = (InDoorView)findViewById(R.id.surface);
  ....
adapter.refreshData();
複製代碼

爲什麼開發 InDoorView?

開發InDoorView的主要目標是解決人與圖片中特殊圖案的交互需求。github

緣起以前我負責的一個app(相似共享短時間工位),主要功能是容許用戶在室內戶型圖上選擇工位,而且點擊某個工位後付費便可把工位點亮。這和咱們常見的電影院選座有點不同,由於大部分區域是非規則圖形,裏面擺放的也是不一樣大小、位置不一的多邊形,不一樣房間也沒法複用,這天然沒法經過循環繪製固定圖形來實現交互。最後,咱們決定採用最多見的標識有區域的 jpg 圖片來作底圖以節約製圖成本,這意味着咱們須要和這些標記區域進行交互。canvas

一開始我使用遊戲引擎來作,該需求並不複雜很快獲得知足,但爲了個簡單功能引入整個庫很是不明智,而且體積也大了很多,加載速度也受到影響。因此我決定着手開發一個能夠精巧的操做圖裏不規則區域的第三方庫。數組

InDoorView 的原理?

把讀取地圖底圖 bitmap 和使用 Paint 的鋼筆路徑集合一同繪製到一個 canvas 上保存,並經過繼承 SurfaceView 把 canvas 繪製到雙緩畫布中,經過 canvas.drawBitmap 實現縮放和移動,重寫 view 點擊事件結合 Region 判斷點擊座標位於哪一個區域內,再經過接口反饋事件。緩存

採用把全部圖案內容事先緩存到 canvas 的方法,使用非 UI 線程進行繪製,可實現每秒 60 次左右的界面繪製,實現流暢的移動和縮放操做;在沒交互狀況下,暫停繪製及刷新以節約計算資源。網絡

特性

  1. 性能較強,繪製達到 60 幀上下
  2. 支持縮放以及拖動
  3. 直接繼承自原生 SurfaceView ,無需導入龐大的引擎庫

接口說明

Activity 中對 view 的控制代碼以下:app

InDoorView view = (InDoorView)findViewById(R.id.surface);
DataAdapter adapter =  new DataAdapter();
view.setAdapter(adapter);//初始化
adapter.setBmp(bmp);//設置圖片(底圖)
adapter.setList(list);//設置數組(圖上的可點區域)
adapter.refreshData();
複製代碼

代碼中的 list 的具體設置看這裏:(輸入鋼筆路徑須要是圖片左上角的相對座標)maven

//每一個圖案的節點座標集合
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 ,網絡加載的圖片則不用

經過該接口能夠返回點擊到的區域的 PathUnit 元素,可經過此來獲取區域名字等信息

view.setOnClickMapListener(new InDoorView.onClickMapListener() {
    @Override
    public void onClick(PathUnit region) {
    //讀取 pathunit
    }
}  
複製代碼

該接口是 fps 幀率

view.onFramesListener(new InDoorView.FramesListener() {
    @Override
    public void onRefresh(float number) {
    //幀率
    }
}    
複製代碼

庫生產環境:

compileSdkVersion 24
minSdkVersion 16

License

Apache License 2.0

相關文章
相關標籤/搜索