利用photoview实现图片的标注以及移动功能

菜鸟进场,方圆十里,寸草不生
今天有一个需求,实现一个标注功能,就是类似于地图开发上的一个marker,只不过背景采用自己上传的图片,然后marker还要实现可以拖拽的功能,大概实现的功能就是这样的:

废话不多说,先说原理,再上代码。
原理:
1、覆盖物图片的拖动:这个简单嘛,网上代码一抓一大把,重点在于初始化相对于图片的位置。

2、覆盖物图片如何跟随背景图移动:利用photoview的放大缩小功能,通过photoview自带的监听来返回图片当前位置信息,然后根据当前的位置来动态设置覆盖物的位置。

好吧,我觉得我也没说清楚。直接上代码!

/**
 * @author zx
 * @date 2018/10/30/030 17:29
 * email [email protected]
 * description  图片标注
 */
public class MainActivity extends AppCompatActivity implements View.OnTouchListener {

    @BindView(R.id.bt_wind)
    Button btWind;
    @BindView(R.id.bt_shade)
    Button btShade;
    @BindView(R.id.bt_rain)
    Button btRain;
    @BindView(R.id.bt_sun)
    Button btSun;
    @BindView(R.id.rl_map)
    RelativeLayout rlMap;
    @BindView(R.id.iv_map)
    PhotoView ivMap;
    @BindView(R.id.iv_reset)
    ImageView ivReset;

    /**
     * 存放动态添加的标注图片
     */
    private List list = new ArrayList<>();


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        ButterKnife.bind(this);
        DensityUtil.init(this);
        setListener();
    }

    private void setListener() {
        /**
         * 设置复位监听
         */
        ivReset.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                /**
                 * 恢复放大倍数(好像photoview不能缩小)
                 */
                ivMap.setScale(1);
            }
        });
        /**
         * photoview图片移动监听(这个返回的位置是背景图相对于左上角与屏幕的相对距离)
         */
        ivMap.setOnMatrixChangeListener(new PhotoViewAttacher.OnMatrixChangedListener() {
            @Override
            public void onMatrixChanged(RectF rect) {
                for (int i = 0; i < list.size(); i++) {
                    ImageView imageView = list.get(i);
                    WeatherBean bean = (WeatherBean) imageView.getTag();
                    if (imageView != null) {
                    	//原始的相对位置乘当前的放大倍数再加上偏移量即当前的相对位置
                        imageView.setX(bean.getPointX() * ivMap.getScale() + rect.left);
                        imageView.setY(bean.getPointY() * ivMap.getScale() + rect.top);
                    }
                }
            }
        });
    }

    /**
     * 点击显示不同的图标,可以对应以后的指示灯什么的
     *
     * @param view
     */
    @OnClick({R.id.bt_wind, R.id.bt_shade, R.id.bt_rain, R.id.bt_sun})
    public void onViewClicked(View view) {
        ImageView imageView = new ImageView(this);
        WeatherBean bean = new WeatherBean();
        switch (view.getId()) {
            case R.id.bt_wind:
                imageView.setImageResource(R.mipmap.wind);
                bean.setKind(1);
                break;
            case R.id.bt_shade:
                bean.setKind(2);
                imageView.setImageResource(R.mipmap.shade);
                break;
            case R.id.bt_rain:
                bean.setKind(3);
                imageView.setImageResource(R.mipmap.rain);
                break;
            case R.id.bt_sun:
                bean.setKind(4);
                imageView.setImageResource(R.mipmap.sun);
                break;
            default:
        }
        imageView.setOnTouchListener(this);
        //不管图片有没有放大,新添加的图标永远出现在右上角
        bean.setPointX(0 - ivMap.getDisplayRect().left);
        bean.setPointY(0 - ivMap.getDisplayRect().top);
        imageView.setTag(bean);
        list.add(imageView);
        rlMap.addView(imageView);
    }

    /**
     * 这个是用来计算手指移动距离的
     */
    float oldX = 0;
    float oldY = 0;

    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
                oldX = event.getRawX();
                oldY = event.getRawY();
                break;
            case MotionEvent.ACTION_MOVE:
                //让控件跟着自己的手指动
                v.setX(v.getX() + event.getRawX() - oldX);
                v.setY(v.getY() + event.getRawY() - oldY);
                oldX = event.getRawX();
                oldY = event.getRawY();
                break;
            case MotionEvent.ACTION_UP:
                //如果在删除区域,就把他给删除掉
                if (v.getX() > DensityUtil.screenWidth - DensityUtil.dip2px(50) && v.getY() < DensityUtil.dip2px(50)) {
                    rlMap.removeView(v);
                }
                WeatherBean bean = (WeatherBean) v.getTag();
                RectF rectF = ivMap.getDisplayRect();
                //计算相对于photoview左边定点的相对位置
                bean.setPointX((v.getX() - rectF.left) / ivMap.getScale());
                bean.setPointY((v.getY() - rectF.top) / ivMap.getScale());
                break;
            default:
        }
        return true;
    }
}

注释在代码里,就是相对位置的计算,感觉我越解释越乱,反正大概也就这么回事儿…
如果有什么不懂的地方,爱莫能助啊。

你可能感兴趣的:(android)