成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久

您的位置:首頁技術文章
文章詳情頁

Android 自定義圖片地圖坐標功能的實現

瀏覽:94日期:2022-09-17 15:50:06
一、前言

最近項目要求實現一個在自定義地圖圖片上添加坐標信息的功能,類似于在圖片做標注的功能。如下圖所示。坐標的位置是相對于圖片寬高的百分比

Android 自定義圖片地圖坐標功能的實現Android 自定義圖片地圖坐標功能的實現

二、思路

改功能主要分為三個視圖,1.繼承FrameLayout作為父容器;2.添加一個鋪滿父布局的ImageView顯示地圖圖片;3.動態添加自定義坐標視圖

三、代碼實現

1. 自定義坐標視圖

<?xml version='1.0' encoding='utf-8'?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android='http://schemas.android.com/apk/res/android' xmlns:app='http://schemas.android.com/apk/res-auto' android:layout_width='wrap_content' android:layout_height='wrap_content'> <ImageViewandroid: android:layout_width='20dp'android:layout_height='wrap_content'android:layout_marginTop='20dp'android:src='http://www.piao2010.com/bcjs/@mipmap/dot2'app:layout_constraintEnd_toStartOf='@+id/tv_sign_name'app:layout_constraintStart_toStartOf='parent'app:layout_constraintTop_toTopOf='parent' /> <TextViewandroid: android:layout_width='80dp'android:layout_height='wrap_content'android:background='@color/white'android:text='美食城'app:layout_constraintEnd_toEndOf='parent'app:layout_constraintTop_toTopOf='parent' /> <TextViewandroid: android:layout_width='80dp'android:layout_height='wrap_content'android:background='@color/teal_200'android:text='正常'android:textColor='@color/white'app:layout_constraintEnd_toEndOf='parent'app:layout_constraintStart_toStartOf='@+id/tv_sign_name'app:layout_constraintTop_toBottomOf='@+id/tv_sign_name' /></androidx.constraintlayout.widget.ConstraintLayout>

class SignView : ConstraintLayout { private val TAG = SignView::class.java.simpleName private var view: View private var signIv: ImageView private var signNameTv: TextView private var signStateTv: TextView constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : super(context, attrs) constructor(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int) : super(context,attrs,defStyleAttr ) init {view = LayoutInflater.from(context).inflate(R.layout.sign_view, this, true)signIv = view.findViewById(R.id.iv_sign)signNameTv = view.findViewById(R.id.tv_sign_name)signStateTv = view.findViewById(R.id.tv_sign_state) } /** * 設置坐標信息 * @param signBean SignBean */ fun setData(signBean: SignBean) {signNameTv.text = signBean.namesignStateTv.text = signBean.state } /** * 計算坐標圖標在整個視圖的偏移量 * @return IntArray */ fun getSignOffset(): IntArray {val w = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)val h = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED)signIv.measure(w, h)val offset = IntArray(2)val signImageWidth = signIv.measuredWidthval signImageHeight = signIv.measuredHeightoffset[0] = signImageWidth / 2offset[1] = 20 + signImageHeight - offset[0]Log.d(TAG, 'getSignOffset: x:${offset[0]}, y:${offset[1]}')return offset }}

自定義的坐標視圖是一個組合的控件,主要是要計算出坐標圖片在整個控件的偏移量

2. 父容器

class MapView : FrameLayout { private val TAG = MapView::class.java.simpleName //地圖圖片 private var mapImage = ImageView(context) private var mapWidth = 0 private var mapHeight = 0 private var mapLeft = 0 private var mapTop = 0 private var signBeanList = listOf<SignBean>() private var signOffsetList = mutableListOf<IntArray>() private var signViewList = mutableListOf<SignView>() private var capturedViewIndex = 0 private val mDragger: ViewDragHelper =ViewDragHelper.create(this, 1.0f, object : ViewDragHelper.Callback() { override fun tryCaptureView(child: View, pointerId: Int): Boolean {return child != mapImage } override fun onViewCaptured(capturedChild: View, activePointerId: Int) {signViewList.forEachIndexed { index, signView -> if (signView == capturedChild) {capturedViewIndex = indexreturn@forEachIndexed }} } override fun onViewPositionChanged(changedView: View,left: Int,top: Int,dx: Int,dy: Int ) {signOffsetList[capturedViewIndex][0] += dxsignOffsetList[capturedViewIndex][1] += dy } override fun clampViewPositionHorizontal(child: View, left: Int, dx: Int): Int {val move = if (left <= mapLeft) mapLeftelse if (left >= mapWidth + mapLeft) mapWidth + mapLeftelse leftreturn move } override fun clampViewPositionVertical(child: View, top: Int, dy: Int): Int {val move = if (top <= mapTop) mapTopelse if (top >= mapHeight + mapTop) mapHeight + mapLeftelse topreturn move }}) constructor(context: Context) : super(context) constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0) constructor(context: Context, attrs: AttributeSet?, @AttrRes defStyleAttr: Int) : this(context,attrs,defStyleAttr,0 ) constructor(context: Context, attrs: AttributeSet?,@AttrRes defStyleAttr: Int, @StyleRes defStyleRes: Int ) : super(context, attrs, defStyleAttr, defStyleRes) /** * 添加地圖圖片 * @param resId Int */ fun setMapImage(@DrawableRes resId: Int) {removeAllViews()mapImage.setImageResource(resId)addView(mapImage) } /** * 設置坐標列表 * @param list List<SignBean> */ fun setSignData(list: List<SignBean>) {val mapOffset = getBitmapOffset(mapImage, true)mapLeft = mapOffset[0]mapTop = mapOffset[1]mapWidth = mapImage.width - mapLeft * 2mapHeight = mapImage.height - mapTop * 2var signOffset = IntArray(2)var boolean = trueLog.d(TAG, 'mapWidth:$mapWidth, mapHeight:$mapHeight, mapLeft:$mapLeft, mapTop:$mapTop')signBeanList = listremoveViews(1, childCount - 1)signViewList.clear()signOffsetList.clear()list.forEach { val signView = SignView(context).apply {setData(it) } // 只需要計算一次 if (boolean) {boolean = falsesignOffset = signView.getSignOffset() } signView.layoutParams = getParams(it, signOffset) addView(signView) signViewList.add(signView) signOffsetList.add(intArrayOf((it.x * mapWidth).toInt(), (it.y * mapHeight).toInt()))} } /** * 獲取移動后的坐標信息 * @return List<SignBean> */ fun getMoveSignData(): List<SignBean> {val data = mutableListOf<SignBean>()signOffsetList.forEachIndexed { index, ints -> val signBean = signBeanList[index] data.add(SignBean( signBean.name, signBean.state, ints[0] / mapWidth.toFloat(), ints[1] / mapHeight.toFloat()) )}return data } /** * 計算坐標位置 * @param signBean SignBean * @return LayoutParams */ private fun getParams(signBean: SignBean, signOffset: IntArray): LayoutParams {val params = LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT)params.setMargins( (signBean.x * mapWidth + mapLeft - signOffset[0]).toInt(), (signBean.y * mapHeight + mapTop - signOffset[1]).toInt(), 0, 0)return params } /** * 計算圖像在ImageView的位移量 * @param img ImageView * @param includeLayout Boolean * @return IntArray? */ private fun getBitmapOffset(img: ImageView, includeLayout: Boolean): IntArray {val offset = IntArray(2)val values = FloatArray(9)val m: Matrix = img.imageMatrixm.getValues(values)offset[0] = values[2].toInt()offset[1] = values[5].toInt()if (includeLayout) { val lp = img.layoutParams as MarginLayoutParams offset[0] += img.paddingLeft + lp.leftMargin offset[1] += img.paddingTop + lp.topMargin}return offset } override fun onInterceptTouchEvent(event: MotionEvent): Boolean {return mDragger.shouldInterceptTouchEvent(event) } override fun onTouchEvent(event: MotionEvent): Boolean {mDragger.processTouchEvent(event)return true }}

父容器中要注意的是由于圖片不拉伸,所以會出現圖片不會完成鋪滿ImageView,會有黑邊。所以要計算出實際圖片顯示的大小。

3. Activity

<?xml version='1.0' encoding='utf-8'?><androidx.constraintlayout.widget.ConstraintLayout xmlns:android='http://schemas.android.com/apk/res/android' xmlns:app='http://schemas.android.com/apk/res-auto' xmlns:tools='http://schemas.android.com/tools' android:layout_width='match_parent' android:layout_height='match_parent' tools:context='.MainActivity'> <com.itc.floatparade.MapViewandroid: android:layout_width='0dp'android:layout_height='0dp'android:layout_marginBottom='12dp'android:background='@color/black'app:layout_constraintBottom_toTopOf='@+id/tv_add_sign'app:layout_constraintEnd_toEndOf='parent'app:layout_constraintStart_toStartOf='parent'app:layout_constraintTop_toTopOf='parent' /> <Buttonandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:layout_marginStart='25dp'android:layout_marginBottom='12dp'android:text='添加坐標'app:layout_constraintBottom_toBottomOf='parent'app:layout_constraintStart_toStartOf='parent' /> <Buttonandroid: android:layout_width='wrap_content'android:layout_height='wrap_content'android:layout_marginEnd='25dp'android:text='獲取坐標'app:layout_constraintBottom_toBottomOf='parent'app:layout_constraintEnd_toEndOf='parent'app:layout_constraintTop_toBottomOf='@+id/map' /> <TextViewandroid: android:layout_width='0dp'android:layout_height='wrap_content'android:layout_marginStart='8dp'android:layout_marginEnd='8dp'android:text=''app:layout_constraintBottom_toBottomOf='parent'app:layout_constraintEnd_toStartOf='@+id/btn_get_sign'app:layout_constraintStart_toEndOf='@+id/tv_add_sign'app:layout_constraintTop_toBottomOf='@+id/map' /></androidx.constraintlayout.widget.ConstraintLayout>

class MainActivity : AppCompatActivity() { private lateinit var binding: ActivityMainBinding override fun onCreate(savedInstanceState: Bundle?) {super.onCreate(savedInstanceState)binding = ActivityMainBinding.inflate(layoutInflater)setContentView(binding.root)binding.map.setMapImage(R.mipmap.map)binding.tvAddSign.setOnClickListener { val list = mutableListOf<SignBean>() list.add(SignBean('美食城', '正常', 0.2f, 0.4f)) list.add(SignBean('恐龍危機', '正常', 0.5f, 0.5f)) list.add(SignBean('海盜船', '正常', 0.7f, 0.6f)) list.add(SignBean('魔法城堡', '正常', 0.4f, 0.8f)) binding.map.setSignData(list)}binding.btnGetSign.setOnClickListener { val list = binding.map.getMoveSignData() binding.tvSignList.text = list.toString()} }}

完整代碼:https://github.com/MattLjp/FloatParade

到此這篇關于Android 自定義圖片地圖坐標的文章就介紹到這了,更多相關Android 自定義地圖內容請搜索好吧啦網以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
成人在线亚洲_国产日韩视频一区二区三区_久久久国产精品_99国内精品久久久久久久
欧美激情一区二区三区在线| 日韩免费看的电影| 亚洲女优在线| 91精品国产一区二区| 亚洲理论在线观看| 成人动漫一区二区三区| 久久精品人人| 国产色婷婷亚洲99精品小说| 国产一区二区三区| 日韩一区在线免费观看| 日韩一区二区在线观看视频播放| 337p日本欧洲亚洲大胆精品| 国产伦精品一区二区三区免费迷| 久久激情久久| 亚洲一区二区三区四区五区黄| 97aⅴ精品视频一二三区| 日韩精品在线网站| 成人精品gif动图一区| 亚洲午夜激情在线| 91天堂素人约啪| 9191成人精品久久| 日韩精品一级二级 | 成人午夜视频在线| 国产精品国产三级国产有无不卡 | 一本久久综合亚洲鲁鲁五月天 | 久久疯狂做爰流白浆xx| 亚洲精品少妇| 国产精品白丝jk黑袜喷水| 日韩欧美在线一区二区三区| 亚洲巨乳在线| 欧美一级午夜免费电影| 国产永久精品大片wwwapp| 91成人国产精品| 图片区小说区国产精品视频| 久久国产精品久久w女人spa| 日韩成人一区二区| 欧美无砖专区一中文字| 国产一区二区三区精品视频| 日韩欧美国产精品一区| 懂色av噜噜一区二区三区av| 2020日本不卡一区二区视频| 欧美.www| 亚洲图片激情小说| 亚洲欧洲精品一区二区| 一区二区三区精品在线观看| 夜久久久久久| 中文字幕一区视频| 亚洲视频日本| 1区2区3区国产精品| 中国成人亚色综合网站| 日本最新不卡在线| 欧美日韩久久久一区| 国产jizzjizz一区二区| 日韩视频一区二区在线观看| 成人高清在线视频| 国产色一区二区| 国产一区二区久久| 欧美一二三在线| 欧美呦呦网站| 中文字幕一区二区三区蜜月| 99香蕉国产精品偷在线观看| 日韩电影在线免费看| 欧美日韩国产小视频| heyzo一本久久综合| 亚洲视频免费在线| 色香蕉成人二区免费| 成人午夜av电影| 中文字幕字幕中文在线中不卡视频| 麻豆精品网站| 国产盗摄一区二区三区| 国产精品乱码久久久久久| 亚洲在线观看| 国产一区二区三区国产| 国产精品视频九色porn| 国产日韩欧美一区| 久久精品国产免费看久久精品| 欧美成人精品高清在线播放| 亚洲私拍自拍| 日本美女一区二区| 亚洲精品在线观看网站| 国产一区二区久久久| 国产精品99久久久久久久vr| 国产精品久线在线观看| 欧美伊人久久久久久久久影院| 成人动漫av在线| 洋洋成人永久网站入口| 欧美老肥妇做.爰bbww视频| 欧美国产专区| 日本亚洲视频在线| 欧美tickling挠脚心丨vk| 亚洲人成高清| 国产乱人伦偷精品视频免下载| 国产日韩欧美一区二区三区综合| 亚洲影音先锋| 国产成人一级电影| 亚洲男帅同性gay1069| 欧美肥胖老妇做爰| 亚洲精品欧美| 国产a级毛片一区| 亚洲专区一二三| 欧美一级一区二区| 国产欧美日本| 成人丝袜视频网| 亚洲国产成人av网| 久久天堂av综合合色蜜桃网| 欧美亚洲专区| eeuss鲁片一区二区三区| 亚洲午夜电影在线| 精品久久久久久久人人人人传媒| 国产欧美日韩综合精品二区| 成人综合婷婷国产精品久久免费| 亚洲国产综合91精品麻豆| 亚洲精品一区二区三区四区高清| 久久精品盗摄| 国产精品国产亚洲精品看不卡15| 国内成人自拍视频| 一区二区三区不卡在线观看| 欧美精品一区二区久久婷婷| 欧美在线制服丝袜| 在线国产欧美| www.亚洲人| 精品制服美女久久| 一区二区三区国产精华| 久久婷婷国产综合精品青草| 91高清视频在线| 在线成人www免费观看视频| 国产91精品久久久久久久网曝门| 亚洲午夜一区二区| 国产欧美综合在线| 51午夜精品国产| 国产一区二区三区久久| 欧美 日韩 国产一区二区在线视频 | 国产精品福利影院| 欧美mv和日韩mv国产网站| 久久亚洲图片| 亚洲久久一区二区| 欧美日韩国产成人精品| 国产999精品久久久久久绿帽| 日本一区中文字幕| 亚洲一区二区三区自拍| 国产精品另类一区| 久久人人97超碰com| 欧美日韩色一区| 一本大道av伊人久久综合| 亚洲国产三级| 97成人超碰视| 懂色av一区二区三区蜜臀| 蜜臀精品一区二区三区在线观看 | 国产91精品一区二区麻豆亚洲| 美腿丝袜亚洲综合| 亚洲高清免费观看高清完整版在线观看 | 婷婷一区二区三区| 尤物在线观看一区| 亚洲欧洲国产专区| 中文字幕av一区 二区| 久久久噜噜噜久久中文字幕色伊伊| 337p亚洲精品色噜噜噜| 欧美色图一区二区三区| 久久国产精品久久久久久电车| 亚洲九九精品| 日韩视频不卡| 亚洲高清精品中出| 在线观看的日韩av| 亚洲高清电影| 999在线观看精品免费不卡网站| 国模精品一区二区三区| 国产一区二区三区无遮挡| 欧美日本二区| 国外精品视频| 激情久久久久久久| 亚洲图片欧洲图片日韩av| 一区二区在线视频观看| 欧美日韩国产高清| 91蝌蚪国产九色| 97成人超碰视| 午夜亚洲福利| 欧美二区视频| 欧美在线观看天堂一区二区三区| 成人h动漫精品一区二区| 丁香一区二区三区| 国产成人免费视| 成人丝袜高跟foot| 91网页版在线| 午夜精品区一区二区三| 欧美日韩在线精品| 亚洲午夜精品一区二区| 亚洲高清精品中出| 在线综合亚洲| 狂野欧美一区| 欧美性生活久久| 884aa四虎影成人精品一区| 欧美一区二区三区四区在线观看| 欧美一区二区三区免费大片 | 日韩午夜电影在线观看| 日韩视频在线你懂得| 精品日韩一区二区三区免费视频| 亚洲精品一区二区三区在线观看| 久久久久久久久伊人| 国产女人18毛片水真多成人如厕| 国产精品女同互慰在线看 |