之前做了一个项目,要在地图上显示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正在整理中