日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区

您的位置:首頁(yè)技術(shù)文章
文章詳情頁(yè)

Android 自定義圖片地圖坐標(biāo)功能的實(shí)現(xiàn)

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

最近項(xiàng)目要求實(shí)現(xiàn)一個(gè)在自定義地圖圖片上添加坐標(biāo)信息的功能,類似于在圖片做標(biāo)注的功能。如下圖所示。坐標(biāo)的位置是相對(duì)于圖片寬高的百分比

Android 自定義圖片地圖坐標(biāo)功能的實(shí)現(xiàn)Android 自定義圖片地圖坐標(biāo)功能的實(shí)現(xiàn)

二、思路

改功能主要分為三個(gè)視圖,1.繼承FrameLayout作為父容器;2.添加一個(gè)鋪滿父布局的ImageView顯示地圖圖片;3.動(dòng)態(tài)添加自定義坐標(biāo)視圖

三、代碼實(shí)現(xiàn)

1. 自定義坐標(biāo)視圖

<?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://m.b3g6.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) } /** * 設(shè)置坐標(biāo)信息 * @param signBean SignBean */ fun setData(signBean: SignBean) {signNameTv.text = signBean.namesignStateTv.text = signBean.state } /** * 計(jì)算坐標(biāo)圖標(biāo)在整個(gè)視圖的偏移量 * @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 }}

自定義的坐標(biāo)視圖是一個(gè)組合的控件,主要是要計(jì)算出坐標(biāo)圖片在整個(gè)控件的偏移量

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) } /** * 設(shè)置坐標(biāo)列表 * @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) } // 只需要計(jì)算一次 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()))} } /** * 獲取移動(dòng)后的坐標(biāo)信息 * @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 } /** * 計(jì)算坐標(biāo)位置 * @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 } /** * 計(jì)算圖像在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 }}

父容器中要注意的是由于圖片不拉伸,所以會(huì)出現(xiàn)圖片不會(huì)完成鋪滿ImageView,會(huì)有黑邊。所以要計(jì)算出實(shí)際圖片顯示的大小。

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='添加坐標(biāo)'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='獲取坐標(biāo)'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('恐龍危機(jī)', '正常', 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

到此這篇關(guān)于Android 自定義圖片地圖坐標(biāo)的文章就介紹到這了,更多相關(guān)Android 自定義地圖內(nèi)容請(qǐng)搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!

標(biāo)簽: Android
相關(guān)文章:
日本不卡不码高清免费观看,久久国产精品久久w女人spa,黄色aa久久,三上悠亚国产精品一区二区三区
国产精品调教| 亚洲欧美高清| 美女亚洲一区| 国产亚洲一区| 免费观看不卡av| 日韩一区自拍| 美女尤物国产一区| 亚洲色图网站| 女人天堂亚洲aⅴ在线观看| 美女视频黄久久| 91精品丝袜国产高跟在线| 国产精品精品| 捆绑调教美女网站视频一区| 视频一区日韩精品| 亚洲一区二区网站| 91九色精品国产一区二区| 福利一区视频| 日韩精品五月天| 欧美日韩国产在线一区| 五月天久久网站| 欧美精品黄色| 久久香蕉精品| 日韩高清三区| 日韩va亚洲va欧美va久久| 亚洲综合图色| 深夜福利一区| 一区二区三区国产在线| 亚洲一二三区视频| 亚洲欧美在线专区| 91av一区| 成人三级高清视频在线看| 日本欧美不卡| 韩日一区二区三区| 好看的亚洲午夜视频在线| 免费日韩视频| 国产精品扒开腿做爽爽爽软件| 国产精品日韩精品中文字幕| 久久久亚洲欧洲日产| 黑人精品一区| 欧美福利专区| 国产午夜久久| 日韩精品久久久久久久软件91| 国产欧美日韩精品一区二区免费| 精品成av人一区二区三区| 亚洲播播91| 视频一区欧美精品| 久久国产精品色av免费看| 精品国产亚洲一区二区三区在线| 日韩av首页| 亚洲一级淫片| 麻豆视频在线看| 亚洲午夜国产成人| 久久精品资源| 丝袜美腿亚洲一区| 福利一区视频| 日韩中文字幕| 精品国产一区二| 亚洲欧美日韩视频二区| 日本精品国产| 亚洲成人不卡| 日韩毛片一区| 欧美在线影院| 免费污视频在线一区| 青草av.久久免费一区| 红桃视频欧美| av资源新版天堂在线| 最近国产精品视频| 在线精品小视频| 欧美成人a交片免费看| 国产精品一线天粉嫩av| 国产一区亚洲| 久久国产视频网| 日韩中文字幕一区二区高清99| 久久精品99国产精品| 只有精品亚洲| 欧美视频久久| 国产精品一区毛片| 国产精品视频一区二区三区四蜜臂 | 亚洲精品2区| 蜜桃免费网站一区二区三区| 日韩在线观看不卡| 国内精品亚洲| 国产一区二区三区四区大秀| 久久精品国产999大香线蕉| 色综合狠狠操| 日韩免费一区| 亚洲成人三区| 亚洲丝袜美腿一区| 日韩在线卡一卡二| 亚洲精品一区三区三区在线观看| 日本一区二区免费高清| 欧美日韩在线播放视频| 亚洲综合中文| 欧美xxxx中国| 国产a亚洲精品| 高潮久久久久久久久久久久久久| 欧美激情日韩| 久久男人av资源站| 国产亚洲一级| 日韩精品免费视频一区二区三区| 欧美片网站免费| 1024精品久久久久久久久| 91伊人久久| 麻豆精品视频在线| 国产精品毛片视频| av中文资源在线资源免费观看| 国产亚洲高清在线观看| 中文字幕在线免费观看视频| 黄色国产精品| 亚洲免费毛片| 麻豆一区二区三区| 久久91导航| 亚洲在线网站| 久久av网站| 欧美日韩少妇| 加勒比视频一区| 午夜在线精品| 福利一区二区免费视频| 红桃视频国产精品| 美女视频免费精品| 中日韩男男gay无套| 国产精品一区亚洲| 欧美亚洲国产激情| 欧美亚洲综合视频| 播放一区二区| 国产精品久久免费视频| 亚洲精品1区2区| 日韩精彩视频在线观看| 国产高清久久| 日韩毛片视频| 国产资源在线观看入口av| 青青国产精品| 蜜桃一区二区三区在线观看| 高清av不卡| 国产私拍福利精品视频二区| 一区二区视频欧美| 亚洲黄色免费看| 国产精品流白浆在线观看| 欧美在线观看天堂一区二区三区| 久久国产电影| 国产成人精品亚洲日本在线观看| 国产精品超碰| 在线精品一区二区| 黄色成人在线网址| 国产在线欧美| 国产资源在线观看入口av| 久久亚州av| 国产福利一区二区精品秒拍| 免费观看在线色综合| 红桃视频欧美| 国产网站在线| 精品无人区麻豆乱码久久久 | 狠狠久久婷婷| 亚洲欧洲一区| 免费日韩视频| 在线亚洲激情| 日韩av中文字幕一区| 欧美一区成人| 午夜精品影视国产一区在线麻豆| 亚洲天堂日韩在线| 欧美一级一区| 精品精品国产三级a∨在线| zzzwww在线看片免费| 欧美日韩精品在线一区| 视频一区二区不卡| 日本综合视频| 国产精品亚洲欧美日韩一区在线 | 久久精品国产99国产| 国产一区二区三区四区大秀| 激情亚洲影院在线观看| 欧美日韩国产一区二区三区不卡| 男女激情视频一区| 欧美国产中文高清| 亚洲免费影视| 久久精品毛片| 日韩视频中文| 国产免费av国片精品草莓男男| 欧美成人a交片免费看| 免费日本视频一区| 黄色欧美在线| 亚洲大全视频| 亚洲欧洲日韩精品在线| 精品国产亚洲日本| 91久久中文| 黄色精品视频| 在线视频免费在线观看一区二区| 国产极品一区| 亚洲欧洲午夜| 久久影院午夜精品| 亚洲伊人影院| 一区二区三区四区在线看| 91九色综合| 国产精品美女| 97精品视频在线看| 日韩精品一区二区三区中文在线| 精品日韩一区| 国产亚洲一区| 无码日韩精品一区二区免费| 国产精久久一区二区| 日本免费新一区视频|