無依賴第三方庫的室內戶型圖交互組件庫
no-dependency Indoor map view library.java
github:github.com/karonl/InDo…(歡迎stars) 該 master branch 爲完整的演示項目,其中 Sample 爲應用模塊,InDoorView 爲庫模塊,LICENSE 爲版權說明。android
該控件可以讓室內圖片上的區域擁有點擊事件,可用於開發電影院選座、商場購物地圖、展位攤位在線預約、辦公場地租賃工位等須要操做不規則區域功能。 若是這正是你所須要的,能夠點擊該庫的 Star (thanks for your star✨),便於收藏學習和關注最新動態。git
allprojects {
repositories {
jcenter()
maven { url 'https://jitpack.io' }
}
}
複製代碼
dependencies {
compile 'com.github.karonl:InDoorSurfaceView:1.0'
}
複製代碼
<com.karonl.instance.InDoorView android:id="@+id/surface" android:layout_width="match_parent" android:layout_height="match_parent" />
複製代碼
InDoorView view = (InDoorView)findViewById(R.id.surface);
....
adapter.refreshData();
複製代碼
開發InDoorView的主要目標是解決人與圖片中特殊圖案的交互需求。github
緣起以前我負責的一個app(相似共享短時間工位),主要功能是容許用戶在室內戶型圖上選擇工位,而且點擊某個工位後付費便可把工位點亮。這和咱們常見的電影院選座有點不同,由於大部分區域是非規則圖形,裏面擺放的也是不一樣大小、位置不一的多邊形,不一樣房間也沒法複用,這天然沒法經過循環繪製固定圖形來實現交互。最後,咱們決定採用最多見的標識有區域的 jpg 圖片來作底圖以節約製圖成本,這意味着咱們須要和這些標記區域進行交互。canvas
一開始我使用遊戲引擎來作,該需求並不複雜很快獲得知足,但爲了個簡單功能引入整個庫很是不明智,而且體積也大了很多,加載速度也受到影響。因此我決定着手開發一個能夠精巧的操做圖裏不規則區域的第三方庫。數組
把讀取地圖底圖 bitmap 和使用 Paint 的鋼筆路徑集合一同繪製到一個 canvas 上保存,並經過繼承 SurfaceView 把 canvas 繪製到雙緩畫布中,經過 canvas.drawBitmap 實現縮放和移動,重寫 view 點擊事件結合 Region 判斷點擊座標位於哪一個區域內,再經過接口反饋事件。緩存
採用把全部圖案內容事先緩存到 canvas 的方法,使用非 UI 線程進行繪製,可實現每秒 60 次左右的界面繪製,實現流暢的移動和縮放操做;在沒交互狀況下,暫停繪製及刷新以節約計算資源。網絡
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
Apache License 2.0