这些天,项目里加了一个功能效果,场景是: 假如有一个家居图片,图片里,有各样的家居用品: 桌子,毛巾,花瓶等等,需要在指定的商品处添加标记,方便用户直接看到商品,点击该标记,可以进入到商品详情页 。实现的效果图如下:

要实现如上效果,有两个思路。

思路1,通过addView,在容器(如FrameLayout)的特定位置,添加标记组件,同事在将ImageView页添加进容器中,保证容器的大小和ImageView的大小相同,这样可以确认标记点的位置不会出现错差。

思路2,通过绘制Bitmap,将背景图片和标记点绘制成同一张图片。

比较两种方法,思路2有些不太妥的地方,1是不好实现标记图标的点击事件;2是不太容易扩展,比如标记点不仅仅是一个图片,而是一个弹框组件,有图有文。 所以,考虑再三后,决定选择第一种实现方式。

1. 自定义布局,包含放置标记图标的容器及显示底部图片的ImageView。

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"><ImageViewandroid:id="@+id/imgBg"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center"android:adjustViewBounds="true"android:maxHeight="1000dp"android:scaleType="centerCrop" /><FrameLayoutandroid:id="@+id/layouPoints"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_gravity="center" /></FrameLayout>

2. 自定义组件,便于添加标记图标、加载背景图

import android.content.Context;
import android.graphics.drawable.AnimationDrawable;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.Toast;import com.bumptech.glide.Glide;
import com.lnyp.imgdots.R;
import com.lnyp.imgdots.bean.PointSimple;import java.util.ArrayList;public class ImageLayout extends FrameLayout implements View.OnClickListener {ArrayList<PointSimple> points;FrameLayout layouPoints;ImageView imgBg;Context mContext;public ImageLayout(Context context) {this(context, null);}public ImageLayout(Context context, AttributeSet attrs) {this(context, attrs, 0);}public ImageLayout(Context context, AttributeSet attrs, int defStyleAttr) {super(context, attrs, defStyleAttr);initView(context, attrs);}private void initView(Context context, AttributeSet attrs) {mContext = context;View imgPointLayout = inflate(context, R.layout.layout_imgview_point, this);imgBg = (ImageView) imgPointLayout.findViewById(R.id.imgBg);layouPoints = (FrameLayout) imgPointLayout.findViewById(R.id.layouPoints);}public void setImgBg(int width, int height, String imgUrl) {ViewGroup.LayoutParams lp = imgBg.getLayoutParams();lp.width = width;lp.height = height;imgBg.setLayoutParams(lp);ViewGroup.LayoutParams lp1 = layouPoints.getLayoutParams();lp1.width = width;lp1.height = height;layouPoints.setLayoutParams(lp1);Glide.with(mContext).load(imgUrl).asBitmap().into(imgBg);addPoints(width, height);}public void setPoints(ArrayList<PointSimple> points) {this.points = points;}private void addPoints(int width, int height) {layouPoints.removeAllViews();for (int i = 0; i < points.size(); i++) {double width_scale = points.get(i).width_scale;double height_scale = points.get(i).height_scale;LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_point, this, false);ImageView imageView = (ImageView) view.findViewById(R.id.imgPoint);imageView.setTag(i);AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();animationDrawable.start();LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();layoutParams.leftMargin = (int) (width * width_scale);layoutParams.topMargin = (int) (height * height_scale);imageView.setOnClickListener(this);layouPoints.addView(view, layoutParams);}}@Overridepublic void onClick(View view) {int pos = (int) view.getTag();Toast.makeText(getContext(), "pos : " + pos, Toast.LENGTH_SHORT).show();}
}

来看看ImageLayout源码,里面有两个重要的方法:

·public void setImgBg(int width, int height, String imgUrl) 该方法主要根据图片的大小,设置标记图容器的大小,然后加载背景图。

·private void addPoints(int width, int height)  该方法主要向记图容器中添加标记图。

3.PointSimple.java

public class PointSimple {// 标记点相对于横向的宽度的比例public double width_scale;// 标记点相对于横向的高度的比例public double height_scale;}

4. 添加背景图和标记图

4.1 首先,准备一些测试数据

 private void initData() {imgSimples = new ArrayList<>();ImgSimple imgSimple1 = new ImgSimple();imgSimple1.url = "http://o79w6dswy.bkt.clouddn.com/img5.png";imgSimple1.scale = 1.6f;ArrayList<PointSimple> pointSimples = new ArrayList<>();PointSimple pointSimple1 = new PointSimple();pointSimple1.width_scale = 0.36f;pointSimple1.height_scale = 0.75f;PointSimple pointSimple2 = new PointSimple();pointSimple2.width_scale = 0.64f;pointSimple2.height_scale = 0.5f;PointSimple pointSimple3 = new PointSimple();pointSimple3.width_scale = 0.276f;pointSimple3.height_scale = 0.764f;PointSimple pointSimple4 = new PointSimple();pointSimple4.width_scale = 0.638f;pointSimple4.height_scale = 0.74f;PointSimple pointSimple5 = new PointSimple();pointSimple5.width_scale = 0.796f;pointSimple5.height_scale = 0.526f;PointSimple pointSimple6 = new PointSimple();pointSimple6.width_scale = 0.486f;pointSimple6.height_scale = 0.364f;pointSimples.add(pointSimple1);pointSimples.add(pointSimple2);pointSimples.add(pointSimple3);pointSimples.add(pointSimple4);pointSimples.add(pointSimple5);pointSimples.add(pointSimple6);imgSimple1.pointSimples = pointSimples;ImgSimple imgSimple2 = new ImgSimple();imgSimple2.url = "http://o79w6dswy.bkt.clouddn.com/img3.png";imgSimple2.scale = 1.6f;ArrayList<PointSimple> pointSimples2 = new ArrayList<>();PointSimple pointSimple7 = new PointSimple();pointSimple7.width_scale = 0.36f;pointSimple7.height_scale = 0.75f;PointSimple pointSimple8 = new PointSimple();pointSimple8.width_scale = 0.64f;pointSimple8.height_scale = 0.5f;PointSimple pointSimple9 = new PointSimple();pointSimple9.width_scale = 0.276f;pointSimple9.height_scale = 0.764f;pointSimples2.add(pointSimple7);pointSimples2.add(pointSimple8);pointSimples2.add(pointSimple9);imgSimple2.pointSimples = pointSimples2;ImgSimple imgSimple3 = new ImgSimple();imgSimple3.url = "http://o79w6dswy.bkt.clouddn.com/421428.jpg";imgSimple3.scale = 0.75f;ArrayList<PointSimple> pointSimples3 = new ArrayList<>();PointSimple pointSimple11 = new PointSimple();pointSimple11.width_scale = 0.1f;pointSimple11.height_scale = 0.3f;PointSimple pointSimple12 = new PointSimple();pointSimple12.width_scale = 0.3f;pointSimple12.height_scale = 0.5f;PointSimple pointSimple13 = new PointSimple();pointSimple13.width_scale = 0.5f;pointSimple13.height_scale = 0.8f;pointSimples3.add(pointSimple11);pointSimples3.add(pointSimple12);pointSimples3.add(pointSimple13);imgSimple3.pointSimples = pointSimples3;imgSimples.add(imgSimple1);imgSimples.add(imgSimple2);imgSimples.add(imgSimple3);}

4.2 加载图片和添加标记物,因为要做可以滑动展示的效果,所以在ViewPager的PagerAdapter中进行功能添加。

import android.app.Activity;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;import com.lnyp.imgdots.R;
import com.lnyp.imgdots.bean.ImgSimple;
import com.lnyp.imgdots.bean.PointSimple;
import com.lnyp.imgdots.view.ImageLayout;import java.util.ArrayList;
import java.util.List;public class ImgBrowsePagerAdapter extends PagerAdapter {List<ImgSimple> imgSimples;List<View> views;Activity mContext;private int width;public ImgBrowsePagerAdapter(Activity context, List<ImgSimple> imgSimples) {this.mContext = context;this.imgSimples = imgSimples;this.views = new ArrayList<>();DisplayMetrics dm = new DisplayMetrics();context.getWindowManager().getDefaultDisplay().getMetrics(dm);width = dm.widthPixels;}@Overridepublic int getCount() { // 获得sizereturn imgSimples.size();}@Overridepublic boolean isViewFromObject(View arg0, Object arg1) {return arg0 == arg1;}@Overridepublic void destroyItem(ViewGroup container, int position, Object object) {((ViewPager) container).removeView((View) object);}@Overridepublic Object instantiateItem(ViewGroup container, int position) {LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_browse, null);ImageLayout layoutContent = (ImageLayout) view.findViewById(R.id.layoutContent);try {String imgUrl = imgSimples.get(position).url;float scale = imgSimples.get(position).scale;ArrayList<PointSimple> pointSimples = imgSimples.get(position).pointSimples;layoutContent.setPoints(pointSimples);int height = (int) (width * scale);layoutContent.setImgBg(width, height, imgUrl);} catch (Exception e) {e.printStackTrace();}((ViewPager) container).addView(view);return view;}
}

4.3 适配器的布局文件layout_img_browse.xml,其中包含了上方自定义的组件ImageLayout

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:gravity="center"android:orientation="vertical"><com.lnyp.imgdots.view.ImageLayoutandroid:id="@+id/layoutContent"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_centerInParent="true" /></LinearLayout>

此处,稍微讲下ImgBrowsePagerAdapter的instantiateItem(ViewGroup container, int position)方法,在该方法中,我们 根据屏幕的宽度,对图片进行等比缩放,计算出了缩放后图片的大小(height和width), 该height和width也就是我们将要添加标记物所在的容器的大小。

通过加载了布局文件,获取ImageLayout对象; 然后,有了这个对象,及计算出的height和width,我们就可以动态的添加背景图及标记物的位置。

因为图片是经过等比缩放的,而标记物的位置是相对于图片的,所以在相同大小的容器添加标记物,它的位置不会出现偏差。

通过以上几步,便可以实现前面动态图中的功能效果了。

如有疑问或建议,欢迎进QQ群讨论:487786925( Android研发村 )

项目github地址:https://github.com/zuiwuyuan/ImgDots

Android 在图片的指定位置添加标记相关推荐

  1. android 动画 图片从指定位置飞到指定位置

    private ViewGroup anim_mask_layout;//动画层 private ImageView sendFeather;// 这是在界面上跑的小图片 </pre>&l ...

  2. C#实现在现有图片的指定位置添加文字

    添加引用: using System.Drawing; using System.Drawing.Imaging; public Bitmap CreateBMP(Image image){//声明位 ...

  3. python使用matplotlib可视化线图(line plot)、在可视化图像中的指定位置添加横线(add horizontal line in matplotlib plot)

    python使用matplotlib可视化线图(line plot).在可视化图像中的指定位置添加横线(add horizontal line in matplotlib plot) 目录

  4. pandas在dataframe指定位置添加新的数据列、使用insert函数

    pandas在dataframe指定位置添加新的数据列.使用insert函数 目录 pandas在dataframe指定位置添加新的数据列.使用insert函数 #仿真数据

  5. R语言ggplot2包和ggtext包在可视化图像中的指定位置添加文本框(横向文本框、竖向文本框)

    R语言ggplot2包和ggtext包在可视化图像中的指定位置添加文本框(横向文本框.竖向文本框) 目录

  6. js 对表格的动态操作(动态添加行,删除该行,在指定位置添加控件)

    ***************************************************************** js动态添加表的列,并在列中添加控件的方法<html> ...

  7. poi操作word替换模板向指定位置添加图表

    poi操作word替换模板向指定位置添加图表 首先是引入pom文件 <dependency><groupId>org.apache.poi</groupId>< ...

  8. java根据坐标在PDF指定位置添加文本

    目录 一.使用Aspose 1.前言: 2.创建一个模型 3.demo测试 二.使用Itext 1.前言 2.创建模型 3.测试demo 1)测试方法 2)实现代码 三.效果展示 一.使用Aspose ...

  9. Python向DataFrame中指定位置添加一列或多列

    对于这个问题,相信很多人都会很困惑,本篇文章将会给大家介绍一种非常简单的方式向DataFrame中任意指定的位置添加一列. 在此之前或许有不少读者已经了解了最普通的添加一列的方式,如下: import ...

最新文章

  1. Mysql—(1)—
  2. Everything排除某个目录、隐藏文件、系统文件
  3. 如何用conda安装软件|处理conda安装工具的动态库问题
  4. 《数据库系统实训》实验报告——单表查询
  5. VS.NET 学习方法论——我的VS.NET学习之旅
  6. 雾计算精华问答 | 雾计算是如何构成的?
  7. 不要错过!MICCAI 2019 所有论文完整下载
  8. 怎么增加服务器容量,新睿云服务器硬盘容量怎么增加?
  9. C语言 NUL、NULL及eof
  10. 上海戏剧学院开学计算机考试,2021年上海戏剧学院大一新生转专业及入学考试相关规定...
  11. android通过adb截取屏幕、录制屏幕 screencap screenrecord
  12. 计算机可移动磁盘无法显示图片,电脑显示可移动磁盘但打不开
  13. 百词斩不复习_也说说百词斩的缺点
  14. 初学docker理解二
  15. 利用Dism修复系统步骤,以及dism找不到源文件解决方案
  16. 电磁场与仿真软件(19)
  17. 支付开发(七)----支付宝开发之手机网站支付(H5支付)
  18. 51单片机——秒表(定时器实现)
  19. 时间序列--自回归模型
  20. 数据库基础SQL知识面试题一

热门文章

  1. 如何用软件测试交易系统的胜率,通达信官网程序交易测试
  2. 3d打印利器FreeCAD入门教程之二----乐高积木块建模操作篇
  3. Unity Addressable学习笔记二(Hosting热更新)
  4. java输入十个,键盘输入十个数,输出最大数
  5. css 默认显示滚动条,css控制默认滚动条样式
  6. matlab 球坐标绘图,在Matlab中绘制球坐标系
  7. Android自定义弹窗模仿微信,Android 仿微信朋友圈点赞和评论弹出框功能
  8. IoT僵尸网络Miori通过ThinkPHP远程代码执行漏洞进行传播
  9. html如何画出四个圆圈,css3如何绘制一个圆圆的loading转圈动画
  10. The process has been signaled with signal '5'. 解决办法