百度地图实现浮动信息框自动排列功能

之前做了一个项目,要在地图上显示Marke的信息,如果两个marker的坐标一样,在地图上显示有可能造成其中一个marker会被另一个覆盖掉。查询百度地图api没有对应的解决方式。所以使用在地图上创建TextView的方式,使用算法动态计算view的位置,实现信息框浮动的功能。啥也不说啦,先上效果图

悬浮框实体类

public class MarkerInfoFloatBean implements Comparable<MarkerInfoFloatBean> {
    private Context context;


    private Rect rect;//字体宽高
    private String name;//名字
    private LatLng latLng;//源坐标

    private int withb;//屏幕宽度
    private int hightb;//屏幕高度
    private Point point;//坐标对应的屏幕点

    private boolean isShow;//显示或隐藏状态

    private TextView textView;//文本

    public MarkerInfoFloatBean(Context context) {
        this.context = context;
        isShow = true;
    }


    public boolean isShow() {
        return isShow;
    }

    public void setShow(boolean show) {
        isShow = show;
    }

    public Rect getRect() {
        return rect;
    }


    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
        textView = new TextView(context);
        textView.setText(name);
        textView.setTextSize(12);
        textView.setBackgroundResource(R.drawable.infor_window_party);
        textView.setTextColor(context.getResources().getColor(R.color.cc_blue));
        textView.measure(0,0);
        int with = textView.getMeasuredWidth();
        int higth = textView.getMeasuredHeight();
        setWithb(with);
        setHightb(higth);
        rect = new Rect();
        rect.set(0,0,with,higth);

    }

    public LatLng getLatLng() {
        return latLng;
    }

    public void setLatLng(LatLng latLng) {
        this.latLng = latLng;
    }

    public void setPoint(Point point) {
        this.point = point;
    }

    public Point getPoint() {
        return point;
    }

    public TextView getTextView() {
        return textView;
    }

    public int getWithb() {
        return withb;
    }

    public void setWithb(int withb) {
        this.withb = withb;
    }

    public int getHightb() {
        return hightb;
    }

    public void setHightb(int hightb) {
        this.hightb = hightb;
    }


    @Override
    public boolean equals(Object obj) {
        if (obj instanceof MarkerInfoFloatBean) {
            return this.getPoint().y == ((MarkerInfoFloatBean)obj).getPoint().y;
        }
        return false;
    }

    @Override
    public int compareTo(@NonNull MarkerInfoFloatBean o) {
        return compare(this.getPoint().y, o.getPoint().y);
    }

    public static int compare(int x, int y) {
        return (x < y) ? -1 : ((x == y) ? 0 : 1);
    }
}

 画线实体类

/**
 * 画线浮动框与Marke点之间的那条线的类
 */
public class LineView extends View {
    private int coloer2 = Color.parseColor("#259bfb");//前景线颜色
    private List<MarkerInfoFloatBean> list;
    private Paint mPaint;//画笔
    private boolean clear;

    public LineView(Context context) {
        this(context,null);
    }

    public LineView(Context context, @Nullable AttributeSet attrs) {
        this(context, attrs,0);
    }

    public LineView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
        super(context, attrs, defStyleAttr);
        initPaint();
        initCricerPaint(coloer2,5);
    }

    public List<MarkerInfoFloatBean> getList() {
        return list;
    }

    public void setList(List<MarkerInfoFloatBean> list) {
        this.list = list;
        invalidate();
    }

    public boolean isClear() {
        return clear;
    }

    public void setClear(boolean clear) {
        this.clear = clear;
        invalidate();
    }

    public int getColoer2() {
        return coloer2;
    }

    public void setColoer2(int coloer2) {
        this.coloer2 = coloer2;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
        if (clear)return;
        DrawLine(canvas);
    }

    private void initPaint(){
        mPaint = new Paint();
    }

    /**
     * 设置画笔颜色
     * @param coloer1
     */
    private void initCricerPaint(int coloer1,int mWith) {
        mPaint.setStrokeWidth(mWith);
        mPaint.setColor(coloer1);
        mPaint.setStyle(Paint.Style.FILL);
    }

    private void DrawLine(Canvas canvas){
        if (list==null)return;
        for (int i=0;i<list.size();i++){
            List<Point> listp = ansalyList(list.get(i));
            if (listp==null||listp.size()<2||!list.get(i).isShow()) continue;
            Point point1 = listp.get(0);
            Point point2 = listp.get(1);
            canvas.drawLine(point1.x,point1.y,point2.x,point2.y,mPaint);//画线
        }
    }

    /**
     * 分析线段两个点的坐标位置
     * @param bean
     * @return
     */
    private List<Point> ansalyList(MarkerInfoFloatBean bean){
        if (bean.getPoint()==null) return null;
        List<Point> list = new ArrayList<>();
        list.add(bean.getPoint());//获取Marke坐标的像素点
        int with = 0;
        int higth = 0;
        if (bean.getTextView().getX()<bean.getPoint().x){//判断悬浮框在marke的左边还是右边
            with = (int) (bean.getTextView().getX()+bean.getWithb());
        }else {
            with = (int) bean.getTextView().getX();
        }
        if (bean.getTextView().getY()<bean.getPoint().y){//判断悬浮框是在marke的上边还是下边
            higth = (int) (bean.getTextView().getY()+bean.getHightb());
        }else {
            higth = (int) bean.getTextView().getY();
        }
        list.add(new Point(with,higth));
        return list;
    }
}

分析悬浮框位置的实体类

/**
 * 分析悬浮框位置的类
 */
public class MarkerPositionPlanUtill {
    private final static int RTE = 100;
    private int with;
    private int hight;
    private int meastWith;
    private List<List<Point>> listList;

    public MarkerPositionPlanUtill(int with, int hight) {
        this.with = with;
        this.hight = hight;
        listList = new ArrayList<>();
        meastWith = with/RTE;
        for (int i=0;i<meastWith;i++){
            listList.add(new ArrayList<Point>());
        }
    }

    /**
     * 规划所有悬浮框的位置
     * @param list
     */
    public void PostionPlaning(List<MarkerInfoFloatBean> list){
        List<Point> list1 = new ArrayList<>();
        for (int i=0;i<list.size();i++){
            list1.add(list.get(i).getPoint());
            list.get(i).setShow(true);//全部显示装填
        }
        NormalAnalysisPoint(list1);//分析坐标
        List<Integer> integerList = getAverageValue();//获取平均值
        Collections.sort(integerList);//排序
        List<List<MarkerInfoFloatBean>> listList = NormalAnalysisBean(integerList,list);//分布数据
        NormalAnalysisBeanYX(integerList,listList);
        NormalAnalysisBeanHide(list);//判断并隐藏重叠的悬浮框
    }


    /**
     * 判断并隐藏重叠的悬浮框
     * @param list
     */
    private void NormalAnalysisBeanHide(List<MarkerInfoFloatBean> list) {
        for (int i=0;i<list.size();i++){
            MarkerInfoFloatBean bean = list.get(i);
            if (!bean.isShow())continue;
            for (int k=0;k<list.size();k++){
                if (k==i||!list.get(k).isShow())continue;
                if (overlayArea(bean.getTextView(),list.get(k).getTextView())>0){
                    bean.setShow(false);
                }
            }
        }
    }

    /**
     * 对计算后的Y轴重新赋值
     * @param list
     */
    private void NormalAnalysisBeanResetY(List<MarkerInfoFloatBean> list) {
        for (int i=0;i<list.size();i++){
            MarkerInfoFloatBean bean = list.get(i);
            for (int k=i;k<list.size()-i;k++){
                if (k==i)continue;
                float ax = bean.getTextView().getX();
                float ay = bean.getTextView().getY();
                float bx = list.get(k).getTextView().getX();
                float by = list.get(k).getTextView().getY();
                if ((bx<=ax+bean.getWithb())&&(by<ay+bean.getHightb())){
                    list.get(k).getTextView().setY(ay+bean.getHightb()+10);
                }
            }
        }
    }

    /**
     * 计算悬浮框偏移后的位置
     * @param integerList
     * @param listList
     */
    private void NormalAnalysisBeanYX(List<Integer> integerList, List<List<MarkerInfoFloatBean>> listList) {
        for (int i=0;i<listList.size();i++){
            List<MarkerInfoFloatBean> list = listList.get(i);
            Collections.sort(list);//单列y坐标排序
            if (list==null||list.size()<=0)return;
            // 根据锚点偏移如果所有情况都有重合则不显示
            for (int k=0;k<list.size();k++){
                int higth = list.get(k).getHightb();//窗口高度
                int top = list.get(k).getPoint().y;//定点y坐标
                list.get(k).getTextView().setX(list.get(k).getPoint().x+60);//窗口横坐标又偏移60
                if (k==0){
                    list.get(k).getTextView().setY(list.get(k).getPoint().y-60);//如果是第一列向左偏移60
                    list.get(k).getTextView().setY(top-higth-60);//向上偏移
                    continue;
                }
                int bottom = list.get(k-1).getPoint().y+list.get(k-1).getHightb();
                if (top<=bottom){
                    list.get(k).getTextView().setX(list.get(k).getPoint().x-list.get(k).getWithb()-60);
                }

                list.get(k).getTextView().setY(top-higth-60);
            }
            NormalAnalysisBeanResetY(list);//对y轴重新赋值
        }
    }


    /**
     * 分析坐标点
     * @param list
     */
    public void NormalAnalysisPoint(List<Point> list){
        for (int i=0;i<list.size();i++){
            for (int k=0;k<meastWith;k++){
                if (k*with<=list.get(i).x&&list.get(i).x<=(k+1)*with){
                    listList.get(k).add(list.get(i));
                }
            }
        }
    }

    /**
     * 获取分布密集处的平均值
     * @return
     */
    public List<Integer> getAverageValue(){
        List<Integer> integerList = new ArrayList<>();
        int allWith = 0;
        for (int i=0;i<listList.size();i++){
            Integer integer = new Integer(0);
            for (Point point:listList.get(i)){
                integer+=point.x;
            }
            allWith+=meastWith;
            if (listList.get(i).size()==0){
//                integerList.add(new Integer(allWith));
                continue;
            }
            integer = integer/listList.get(i).size();
            integerList.add(integer);
        }
        return integerList;
    }

    /**
     * 正态分布数据
     * @param integerList
     * @param list
     * @return
     */
    public List<List<MarkerInfoFloatBean>> NormalAnalysisBean(List<Integer> integerList,List<MarkerInfoFloatBean> list){
        List<List<MarkerInfoFloatBean>> lists = new ArrayList<>();
        for (int i=0;i<integerList.size();i++){
            List<MarkerInfoFloatBean> infoFloatBeans = new ArrayList<>();
            for (int k=0;k<list.size();k++){
                if (i==0){
                    if (0<=list.get(k).getPoint().x&&
                            list.get(k).getPoint().x<integerList.get(i)){
                        infoFloatBeans.add(list.get(k));
                    }
                    continue;
                }
                if (integerList.get(i-1)<=list.get(k).getPoint().x&&
                        list.get(k).getPoint().x<integerList.get(i)){
                    infoFloatBeans.add(list.get(k));
                }
            }
            lists.add(infoFloatBeans);
        }
        return lists;
    }


    /**
     * 计算重叠面积。如果返回大于0,表示view1与view2有碰撞。
     * @param view1
     * @param view2
     * @return 重叠面积
     */
    public float overlayArea(View view1, View view2){
        float area=0;
        if(view1!=null && view2!=null){

            //view2-左上a,右上b,左下c,右下d
            //view1-左上e,右上f,左下g,右下h
            //重叠部分-左上w,右上x,左下y,右下z

            //view2
            float width2=view2.getWidth();
            float height2=view2.getHeight();
            float ax=view2.getX();
            float ay=view2.getY();
            float bx=ax+width2;
//    		float by=ay;
//    		float cx=ax;
            float cy=ay+height2;
//    		float dx=ax+width2;
//    		float dy=ay+height2;

            //view1
            float width1=view1.getWidth();
            float height1=view1.getHeight();
            float ex=view1.getX();
            float ey=view1.getY();
            float fx=ex+width1;
//    		float fy=ey;
//    		float gx=ex;
            float gy=ey+height1;
//    		float hx=ex+width1;
//    		float hy=ey+height1;

            if(bx<ex || fx<ax || cy<ey || gy<ay){
                //没有重叠部分

            }else{
                //重叠部分
                float wx=ax>ex?ax:ex;
                float wy=ay>ey?ay:ey;
                float xx=bx<fx?bx:fx;
//        		float xy=by>fy?by:fy;
//        		float yx=cx>gx?cx:gx;
                float yy=cy<gy?cy:gy;
//        		float zx=dx<hx?dx:hx;
//        		float zy=dy<hy?dy:hy;

                //计算重叠面积
                float width=xx-wx;
                float height=yy-wy;
                area=width*height;
            }

        }
        return area;
    }


}

 调用

    public void upDataFloatInfoView(boolean flag) {
        if (mBaiduMap == null) return;
        for (int i = 0; i < markerInfoFloatBeans.size(); i++) {
            View view = layout_view_info_float.getChildAt(i);
            MarkerInfoFloatBean bean = markerInfoFloatBeans.get(i);
            bean.setPoint(mPresenter.latLngToPoint(mBaiduMap, bean.getLatLng()));//将坐标转成像素点
            view.setY(bean.getPoint().y);
            view.setX(bean.getPoint().x);
            if (flag) {
                view.setVisibility(View.VISIBLE);
            } else {
                view.setVisibility(View.GONE);
            }
        }
        if (!flag) {
            view_line_drow.setClear(flag);
            return;
        }
        positionPlanUtill.PostionPlaning(markerInfoFloatBeans);//调用悬浮框位置分析的方法
        for (int i = 0; i < markerInfoFloatBeans.size(); i++) {
            if (markerInfoFloatBeans.get(i).isShow()) {
                markerInfoFloatBeans.get(i).getTextView().setVisibility(View.VISIBLE);
            } else {
                markerInfoFloatBeans.get(i).getTextView().setVisibility(View.GONE);
            }
        }
        view_line_drow.setList(markerInfoFloatBeans);//画线
    }

Demo正在整理中

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值