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

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

思路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"> <ImageView
android: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" /> <FrameLayout
android: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);
}
} @Override
public 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;
} @Override
public int getCount() { // 获得size
return imgSimples.size();
} @Override
public boolean isViewFromObject(View arg0, Object arg1) {
return arg0 == arg1;
} @Override
public void destroyItem(ViewGroup container, int position, Object object) { ((ViewPager) container).removeView((View) object);
} @Override
public 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.ImageLayout
android: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. Dom4j向XML中指定位置添加、删除、修改节点——(五)

    需求: 在第一本书作者后面增加描述 <描述>好书</描述>  思路:获取书下面下的所有节点(一个list集合),在list集合指定位置添加一个元素(list.add(index ...

  2. javascript数组在指定位置添加和删除元素

    在JavaScript中,Array对象提供了一个强大的splice()方法,利用这个方法可以达到在数组的指定位置添加和删除元素的目的. 指定位置删除元素 要在指定位置删除元素,可以使用splice( ...

  3. DataTable 指定位置添加列

    dt.Columns.Add("id").SetOrdinal(指定位置);

  4. jQuery如何追加tr到table中任意位置--向Table中指定位置添加tr或td(jQuery)

    jQuery 添加新内容有以下四个方法: append() - 在被选元素的结尾插入内容 prepend() - 在被选元素的开头插入内容 after() - 在被选元素之后插入内容 before() ...

  5. ajax中向HTML页面中指定位置添加信息

    $.ajax({  type : "POST",  beforeSend : function() {   showLoader("数据加载中...");// ...

  6. android学习——popupWindow 在指定位置上的显示

    先看效果图,免得浪费大家时间,看是不是想要的效果 . 直接上代码 ,核心方法. [java] view plaincopy private void showPopupWindow(View pare ...

  7. js数组指定位置添加删除

    示例参考:http://www.w3school.com.cn/jsref/jsref_splice.asp

  8. C#DataTable添加列、C#指定位置添加列

    DataSet ds = SQlHelper.GetDataTable(Con, sb.ToString()); ds.Tables[].Columns.Add("Check", ...

  9. Android RecyView 滑动置指定位置

    1,直接回到顶部 recyview.getLinearLayoutManager().scrollToPositionWithOffset(0, 0); 2,慢慢的回到顶部 private void ...

随机推荐

  1. mac vagrant 虚拟机nfs挂载点

    需求:在mac 上安装了虚拟机,虚拟机系统为centos6.5,现在希望讲虚拟机上点目录通过nfs共享给mac使用 下面主要描述通过nfs共享目录给mac调用的过程 过程参考网址: http://ww ...

  2. .NET框架之---MEF托管可扩展框架

    MEF简介: 今天学习了下MEF框架,MEF,全称Managed Extensibility Framework(托管可扩展框架).MEF是专门致力于解决扩展性问题的框架,MSDN中对MEF有这样一段 ...

  3. 字符串无法分割 split无效: java split()使用“.” “\” "|" "*" "+"要转义

    .是特殊字符 特殊字符需要转义. 改成split(“\\.”)

  4. 2019.8.14 NOIP模拟测试21 反思总结

    模拟测试20的还没改完先咕着 各种细节问题=错失190pts T1大约三分钟搞出了式子,迅速码完,T2写了一半的时候怕最后被卡评测滚去交了,然后右端点没有初始化为n…但是这样还有80pts,而我后来还 ...

  5. linux-基础-常用命令

    一 Linux的简介 1.1 Linux的概述 Linux是基于Unix的开源免费的操作系统,由于系统的稳定性和安全性几乎成为程序代码运行的最佳系统环境.Linux是由Linus Torvalds(林 ...

  6. 【洛谷】P1888 三角函数

    P1888 三角函数 题目描述 输入一组勾股数a,b,c(a≠b≠c),用分数格式输出其较小锐角的正弦值.(要求约分.) 输入输出格式 输入格式: 一行,包含三个数,即勾股数a,b,c(无大小顺序). ...

  7. notepad++ 退出后关闭所有文档(关闭“记住最后打开的文件”)

    旧版本: 设置->首选项->其他->取消勾选Remember current session for next launch 新版本: 设置->首选项->备份->取 ...

  8. Thinkphp 不足之处

    1.报错机制 //控制器里面直接输出如下内容,代码不提示.TP报错机制已经开启 echo $aaaaaa; bbbbbbbbb; eco bbbbbbbb; 正常应该给出以下提示 Notice: Un ...

  9. 解决安装编译工具gcc后无法连接mysql

    在安装编译工具gcc后: yum -y install make gcc g++ gcc-c++ libtool autoconf automake imake mysql-devel libxml2 ...

  10. web前端学习(三)css学习笔记部分(2)-- css定位+盒子操作

    3.CSS定位 3.1定位 1.CSS定位: 改变元素在页面上的位置 2.CSS定位机制 普通流:元素按照其在HTML中的位置顺序决定排布的过程 浮动 绝对布局 属性 描述 position 把元素放 ...