当前位置:   article > 正文

Android 在图片的指定位置添加标记

Android 在图片的指定位置添加标记

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


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

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

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

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


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

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="wrap_content">
  5. <ImageView
  6. android:id="@+id/imgBg"
  7. android:layout_width="match_parent"
  8. android:layout_height="wrap_content"
  9. android:layout_gravity="center"
  10. android:adjustViewBounds="true"
  11. android:maxHeight="1000dp"
  12. android:scaleType="centerCrop" />
  13. <FrameLayout
  14. android:id="@+id/layouPoints"
  15. android:layout_width="match_parent"
  16. android:layout_height="wrap_content"
  17. android:layout_gravity="center" />
  18. </FrameLayout>

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

  1. import android.content.Context;
  2. import android.graphics.drawable.AnimationDrawable;
  3. import android.util.AttributeSet;
  4. import android.view.LayoutInflater;
  5. import android.view.View;
  6. import android.view.ViewGroup;
  7. import android.widget.FrameLayout;
  8. import android.widget.ImageView;
  9. import android.widget.LinearLayout;
  10. import android.widget.Toast;
  11. import com.bumptech.glide.Glide;
  12. import com.lnyp.imgdots.R;
  13. import com.lnyp.imgdots.bean.PointSimple;
  14. import java.util.ArrayList;
  15. public class ImageLayout extends FrameLayout implements View.OnClickListener {
  16. ArrayList<PointSimple> points;
  17. FrameLayout layouPoints;
  18. ImageView imgBg;
  19. Context mContext;
  20. public ImageLayout(Context context) {
  21. this(context, null);
  22. }
  23. public ImageLayout(Context context, AttributeSet attrs) {
  24. this(context, attrs, 0);
  25. }
  26. public ImageLayout(Context context, AttributeSet attrs, int defStyleAttr) {
  27. super(context, attrs, defStyleAttr);
  28. initView(context, attrs);
  29. }
  30. private void initView(Context context, AttributeSet attrs) {
  31. mContext = context;
  32. View imgPointLayout = inflate(context, R.layout.layout_imgview_point, this);
  33. imgBg = (ImageView) imgPointLayout.findViewById(R.id.imgBg);
  34. layouPoints = (FrameLayout) imgPointLayout.findViewById(R.id.layouPoints);
  35. }
  36. public void setImgBg(int width, int height, String imgUrl) {
  37. ViewGroup.LayoutParams lp = imgBg.getLayoutParams();
  38. lp.width = width;
  39. lp.height = height;
  40. imgBg.setLayoutParams(lp);
  41. ViewGroup.LayoutParams lp1 = layouPoints.getLayoutParams();
  42. lp1.width = width;
  43. lp1.height = height;
  44. layouPoints.setLayoutParams(lp1);
  45. Glide.with(mContext).load(imgUrl).asBitmap().into(imgBg);
  46. addPoints(width, height);
  47. }
  48. public void setPoints(ArrayList<PointSimple> points) {
  49. this.points = points;
  50. }
  51. private void addPoints(int width, int height) {
  52. layouPoints.removeAllViews();
  53. for (int i = 0; i < points.size(); i++) {
  54. double width_scale = points.get(i).width_scale;
  55. double height_scale = points.get(i).height_scale;
  56. LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_point, this, false);
  57. ImageView imageView = (ImageView) view.findViewById(R.id.imgPoint);
  58. imageView.setTag(i);
  59. AnimationDrawable animationDrawable = (AnimationDrawable) imageView.getDrawable();
  60. animationDrawable.start();
  61. LayoutParams layoutParams = (LayoutParams) view.getLayoutParams();
  62. layoutParams.leftMargin = (int) (width * width_scale);
  63. layoutParams.topMargin = (int) (height * height_scale);
  64. imageView.setOnClickListener(this);
  65. layouPoints.addView(view, layoutParams);
  66. }
  67. }
  68. @Override
  69. public void onClick(View view) {
  70. int pos = (int) view.getTag();
  71. Toast.makeText(getContext(), "pos : " + pos, Toast.LENGTH_SHORT).show();
  72. }
  73. }
  来看看ImageLayout源码,里面有两个重要的方法:

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


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

3.PointSimple.java

  1. public class PointSimple {
  2. // 标记点相对于横向的宽度的比例
  3. public double width_scale;
  4. // 标记点相对于横向的高度的比例
  5. public double height_scale;
  6. }


4. 添加背景图和标记图

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

  1. private void initData() {
  2. imgSimples = new ArrayList<>();
  3. ImgSimple imgSimple1 = new ImgSimple();
  4. imgSimple1.url = "http://o79w6dswy.bkt.clouddn.com/img5.png";
  5. imgSimple1.scale = 1.6f;
  6. ArrayList<PointSimple> pointSimples = new ArrayList<>();
  7. PointSimple pointSimple1 = new PointSimple();
  8. pointSimple1.width_scale = 0.36f;
  9. pointSimple1.height_scale = 0.75f;
  10. PointSimple pointSimple2 = new PointSimple();
  11. pointSimple2.width_scale = 0.64f;
  12. pointSimple2.height_scale = 0.5f;
  13. PointSimple pointSimple3 = new PointSimple();
  14. pointSimple3.width_scale = 0.276f;
  15. pointSimple3.height_scale = 0.764f;
  16. PointSimple pointSimple4 = new PointSimple();
  17. pointSimple4.width_scale = 0.638f;
  18. pointSimple4.height_scale = 0.74f;
  19. PointSimple pointSimple5 = new PointSimple();
  20. pointSimple5.width_scale = 0.796f;
  21. pointSimple5.height_scale = 0.526f;
  22. PointSimple pointSimple6 = new PointSimple();
  23. pointSimple6.width_scale = 0.486f;
  24. pointSimple6.height_scale = 0.364f;
  25. pointSimples.add(pointSimple1);
  26. pointSimples.add(pointSimple2);
  27. pointSimples.add(pointSimple3);
  28. pointSimples.add(pointSimple4);
  29. pointSimples.add(pointSimple5);
  30. pointSimples.add(pointSimple6);
  31. imgSimple1.pointSimples = pointSimples;
  32. ImgSimple imgSimple2 = new ImgSimple();
  33. imgSimple2.url = "http://o79w6dswy.bkt.clouddn.com/img3.png";
  34. imgSimple2.scale = 1.6f;
  35. ArrayList<PointSimple> pointSimples2 = new ArrayList<>();
  36. PointSimple pointSimple7 = new PointSimple();
  37. pointSimple7.width_scale = 0.36f;
  38. pointSimple7.height_scale = 0.75f;
  39. PointSimple pointSimple8 = new PointSimple();
  40. pointSimple8.width_scale = 0.64f;
  41. pointSimple8.height_scale = 0.5f;
  42. PointSimple pointSimple9 = new PointSimple();
  43. pointSimple9.width_scale = 0.276f;
  44. pointSimple9.height_scale = 0.764f;
  45. pointSimples2.add(pointSimple7);
  46. pointSimples2.add(pointSimple8);
  47. pointSimples2.add(pointSimple9);
  48. imgSimple2.pointSimples = pointSimples2;
  49. ImgSimple imgSimple3 = new ImgSimple();
  50. imgSimple3.url = "http://o79w6dswy.bkt.clouddn.com/421428.jpg";
  51. imgSimple3.scale = 0.75f;
  52. ArrayList<PointSimple> pointSimples3 = new ArrayList<>();
  53. PointSimple pointSimple11 = new PointSimple();
  54. pointSimple11.width_scale = 0.1f;
  55. pointSimple11.height_scale = 0.3f;
  56. PointSimple pointSimple12 = new PointSimple();
  57. pointSimple12.width_scale = 0.3f;
  58. pointSimple12.height_scale = 0.5f;
  59. PointSimple pointSimple13 = new PointSimple();
  60. pointSimple13.width_scale = 0.5f;
  61. pointSimple13.height_scale = 0.8f;
  62. pointSimples3.add(pointSimple11);
  63. pointSimples3.add(pointSimple12);
  64. pointSimples3.add(pointSimple13);
  65. imgSimple3.pointSimples = pointSimples3;
  66. imgSimples.add(imgSimple1);
  67. imgSimples.add(imgSimple2);
  68. imgSimples.add(imgSimple3);
  69. }

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

  1. import android.app.Activity;
  2. import android.support.v4.view.PagerAdapter;
  3. import android.support.v4.view.ViewPager;
  4. import android.util.DisplayMetrics;
  5. import android.view.LayoutInflater;
  6. import android.view.View;
  7. import android.view.ViewGroup;
  8. import android.widget.LinearLayout;
  9. import com.lnyp.imgdots.R;
  10. import com.lnyp.imgdots.bean.ImgSimple;
  11. import com.lnyp.imgdots.bean.PointSimple;
  12. import com.lnyp.imgdots.view.ImageLayout;
  13. import java.util.ArrayList;
  14. import java.util.List;
  15. public class ImgBrowsePagerAdapter extends PagerAdapter {
  16. List<ImgSimple> imgSimples;
  17. List<View> views;
  18. Activity mContext;
  19. private int width;
  20. public ImgBrowsePagerAdapter(Activity context, List<ImgSimple> imgSimples) {
  21. this.mContext = context;
  22. this.imgSimples = imgSimples;
  23. this.views = new ArrayList<>();
  24. DisplayMetrics dm = new DisplayMetrics();
  25. context.getWindowManager().getDefaultDisplay().getMetrics(dm);
  26. width = dm.widthPixels;
  27. }
  28. @Override
  29. public int getCount() { // 获得size
  30. return imgSimples.size();
  31. }
  32. @Override
  33. public boolean isViewFromObject(View arg0, Object arg1) {
  34. return arg0 == arg1;
  35. }
  36. @Override
  37. public void destroyItem(ViewGroup container, int position, Object object) {
  38. ((ViewPager) container).removeView((View) object);
  39. }
  40. @Override
  41. public Object instantiateItem(ViewGroup container, int position) {
  42. LinearLayout view = (LinearLayout) LayoutInflater.from(mContext).inflate(R.layout.layout_img_browse, null);
  43. ImageLayout layoutContent = (ImageLayout) view.findViewById(R.id.layoutContent);
  44. try {
  45. String imgUrl = imgSimples.get(position).url;
  46. float scale = imgSimples.get(position).scale;
  47. ArrayList<PointSimple> pointSimples = imgSimples.get(position).pointSimples;
  48. layoutContent.setPoints(pointSimples);
  49. int height = (int) (width * scale);
  50. layoutContent.setImgBg(width, height, imgUrl);
  51. } catch (Exception e) {
  52. e.printStackTrace();
  53. }
  54. ((ViewPager) container).addView(view);
  55. return view;
  56. }
  57. }
  4.3 适配器的布局文件layout_img_browse.xml,其中包含了上方自定义的组件ImageLayout

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="match_parent"
  4. android:layout_height="match_parent"
  5. android:gravity="center"
  6. android:orientation="vertical">
  7. <com.lnyp.imgdots.view.ImageLayout
  8. android:id="@+id/layoutContent"
  9. android:layout_width="match_parent"
  10. android:layout_height="wrap_content"
  11. android:layout_centerInParent="true" />
  12. </LinearLayout>


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

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

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


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

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

 

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

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/689468
推荐阅读
相关标签
  

闽ICP备14008679号