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


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


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

      思路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

  • 相关阅读:
    微信小程序 简单控件
    #负分小组WEEK1#一个开头&小组介绍
    CountDownLatch使用场景及分析
    Markdown基础语法
    【转】awk的使用及字符串的操作
    【开篇有益】敢问路在何方,佛曰路就在脚下
    【EntityFramework 6.1.3】个人理解与问题记录(2)
    EETOOL简介
    VMware 安装失败 “Failed to create the requested registry key Key:installer Error:1021"
    vs2010调试时为什么会出现clr.dll与mscordacwks.dll版本不匹配?
  • 原文地址:https://www.cnblogs.com/hehe520/p/6329934.html
Copyright © 2020-2023  润新知