电脑知识|欧美黑人一区二区三区|软件|欧美黑人一级爽快片淫片高清|系统|欧美黑人狂野猛交老妇|数据库|服务器|编程开发|网络运营|知识问答|技术教程文章 - 好吧啦网

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

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

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

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

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

二、思路

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

三、代碼實現

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.hdgsjgj.cn/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 自定義地圖內容請搜索好吧啦網以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持好吧啦網!

標簽: Android
相關文章:
主站蜘蛛池模板: 双菱电缆-广州电缆厂_广州电缆厂有限公司 | 天一线缆邯郸有限公司_煤矿用电缆厂家_矿用光缆厂家_矿用控制电缆_矿用通信电缆-天一线缆邯郸有限公司 | 彩信群发_群发彩信软件_视频短信营销平台-达信通 | 宏源科技-房地产售楼系统|线上开盘系统|售楼管理系统|线上开盘软件 | 南京PVC快速门厂家南京快速卷帘门_南京pvc快速门_世界500强企业国内供应商_南京美高门业 | 首页 - 军军小站|张军博客| 代办建筑资质升级-建筑资质延期就找上海国信启航 | 钢结构厂房造价_钢结构厂房预算_轻钢结构厂房_山东三维钢结构公司 | 小型高低温循环试验箱-可程式高低温湿热交变试验箱-东莞市拓德环境测试设备有限公司 | 制丸机,小型中药制丸机,全自动制丸机价格-甘肃恒跃制药设备有限公司 | 安徽净化板_合肥岩棉板厂家_玻镁板厂家_安徽科艺美洁净科技有限公司 | 塑料脸盆批发,塑料盆生产厂家,临沂塑料广告盆,临沂家用塑料盆-临沂市永顺塑业 | 珠海白蚁防治_珠海灭鼠_珠海杀虫灭鼠_珠海灭蟑螂_珠海酒店消杀_珠海工厂杀虫灭鼠_立净虫控防治服务有限公司 | 机制砂选粉机_砂石选粉机厂家-盐城市助成粉磨科技有限公司 | 石磨面粉机|石磨面粉机械|石磨面粉机组|石磨面粉成套设备-河南成立粮油机械有限公司 | 防腐储罐_塑料储罐_PE储罐厂家_淄博富邦滚塑防腐设备科技有限公司 | 防火卷帘门价格-聊城一维工贸特级防火卷帘门厂家▲ | 百方网-百方电气网,电工电气行业专业的B2B电子商务平台 | 中图网(原中国图书网):网上书店,尾货特色书店,30万种特价书低至2折! | 欧美日韩国产一区二区三区不_久久久久国产精品无码不卡_亚洲欧洲美洲无码精品AV_精品一区美女视频_日韩黄色性爱一级视频_日本五十路人妻斩_国产99视频免费精品是看4_亚洲中文字幕无码一二三四区_国产小萍萍挤奶喷奶水_亚洲另类精品无码在线一区 | 济南品牌设计-济南品牌策划-即合品牌策划设计-山东即合官网 | 软文推广发布平台_新闻稿件自助发布_媒体邀约-澜媒宝 | 上海噪音治理公司-专业隔音降噪公司-中广通环保| 炉门刀边腹板,焦化设备配件,焦化焦炉设备_沧州瑞创机械制造有限公司 | 论文查重_免费论文查重_知网学术不端论文查重检测系统入口_论文查重软件 | 广西绿桂涂料--承接隔热涂料、隔音涂料、真石漆、多彩仿石漆等涂料工程双包施工 | TPE_TPE热塑性弹性体_TPE原料价格_TPE材料厂家-惠州市中塑王塑胶制品公司- 中塑王塑胶制品有限公司 | 最新范文网_实用的精品范文美文网| 济南宣传册设计-画册设计_济南莫都品牌设计公司 | 污泥烘干机-低温干化机-工业污泥烘干设备厂家-焦作市真节能环保设备科技有限公司 | ★店家乐|服装销售管理软件|服装店收银系统|内衣店鞋店进销存软件|连锁店管理软件|收银软件手机版|会员管理系统-手机版,云版,App | 五轴加工中心_数控加工中心_铝型材加工中心-罗威斯 | 北京网站建设首页,做网站选【优站网】,专注北京网站建设,北京网站推广,天津网站建设,天津网站推广,小程序,手机APP的开发。 | bng防爆挠性连接管-定做金属防爆挠性管-依客思防爆科技 | 对夹式止回阀_对夹式蝶形止回阀_对夹式软密封止回阀_超薄型止回阀_不锈钢底阀-温州上炬阀门科技有限公司 | 数显恒温培养摇床-卧式/台式恒温培养摇床|朗越仪器 | 顺辉瓷砖-大国品牌-中国顺辉 | 网带通过式抛丸机,,网带式打砂机,吊钩式,抛丸机,中山抛丸机生产厂家,江门抛丸机,佛山吊钩式,东莞抛丸机,中山市泰达自动化设备有限公司 | 医疗仪器模块 健康一体机 多参数监护仪 智慧医疗仪器方案定制 血氧监护 心电监护 -朗锐慧康 | 水上浮桥-游艇码头-浮动码头-游船码头-码瑞纳游艇码头工程 | 东莞韩创-专业绝缘骨架|马达塑胶零件|塑胶电机配件|塑封电机骨架厂家 |