Search code examples
javaandroidosmdroid

Add InfoWindow to a FastPointOverlay - OsmDroid


Initally I had implemented the functionality needed using the Marker class, but when the points where getting more there was a severe degradation of performance, so I used the SimpleFastPointOverlay in combination with the PopUpwindow.

public class OpenMapFragment extends Fragment {
    private Map<Integer, MyPoint> myPointsMap;
    private Context context;
    private PageViewModel pageViewModel;
    private MapView map = null;
    private SimpleFastPointOverlay sfpo;

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getParentFragment() != null) {
            pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
        }
        context = requireActivity().getApplicationContext();

    }

    @Override
    public View onCreateView(
            @NonNull LayoutInflater inflater, ViewGroup container,
            Bundle savedInstanceState) {
        View root = inflater.inflate(R.layout.fragment_open_map, container, false);
        LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
        Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
        map = root.findViewById(R.id.mapview);
        map.setTileSource(TileSourceFactory.MAPNIK);
        map.setMultiTouchControls(true);
        myPointsMap = new HashMap<>();
        pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
           myPointsMap = 
               myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
           if (sfpo != null) {
               map.getOverlays().remove(sfpo);
           }
           sfpo = simpleFastPointOverlayBuilder(myPointsList);
           sfpo.setOnClickListener((points, point) -> {
                MyPoint mp = myPointsMap
                        .get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));

                View popupView = inflater.inflate(R.layout.popup_window, null);
                TextView txtId = popupView.findViewById(R.id.txt_id);
                txtId.setText("id:" + mp.getId());

                int width = LinearLayout.LayoutParams.WRAP_CONTENT;
                int height = LinearLayout.LayoutParams.WRAP_CONTENT;
                final PopupWindow popupWindow = new PopupWindow(popupView, width, height, true);

                popupWindow.showAtLocation(getView(), Gravity.CENTER, 0, 0);

                popupView.setOnTouchListener(new View.OnTouchListener() {
                    @Override
                    public boolean onTouch(View v, MotionEvent event) {
                        popupWindow.dismiss();
                        return true;
                    }
                });
            });
            map.getOverlays().add(sfpo);
        });
        return root;
    }

    private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
        List<IGeoPoint> points = new ArrayList<>();

        Paint textStyle = new Paint();
        textStyle.setStyle(Paint.Style.FILL);
        textStyle.setColor(Color.parseColor("#111111"));
        textStyle.setTextAlign(Paint.Align.CENTER);
        textStyle.setTextSize(24);

        Paint pointStyle = new Paint();
        pointStyle.setStyle(Paint.Style.FILL);
        pointStyle.setColor(Color.rgb(255, 0, 0));

        for(MyPoint myPoint: myPointList) {
            points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
                    myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
                    pointStyle, textStyle));
        }

        SimplePointTheme pointTheme = new SimplePointTheme(points);

        SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
                .setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
                .setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
                .setRadius(7).setIsClickable(true).setCellSize(12)
                .setMinZoomShowLabels(12);
        return new SimpleFastPointOverlay(pointTheme, opt);
    }


    @Override
    public void onResume() {
        super.onResume();
        map.onResume();
    }

    @Override
    public void onPause() {
        super.onPause();
        map.onPause();
    }
}

Although this is a workaround, I do not like it since the popupView is at the center of the display, and cannot be assiciated with the poisition of the clicked element. Is there a way that I could have a similar behavior with the Marker and the InfoWindow of the OsmDroid?


Solution

  • I finally found a solution: In order to have the desired functinality i should add a Marker each time simpleFastPoint was clicked and if another clicked remove the previous and add a new one. So the performance is still great but with the Marker behavior. Also I made the marker invisible

    public class OpenMapFragment extends Fragment {
        private Map<Integer, MyPoint> myPointsMap;
        private Context context;
        private PageViewModel pageViewModel;
        private MapView map = null;
        private SimpleFastPointOverlay sfpo;
        private Marker marker;
    
        @Override
        public void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            if (getParentFragment() != null) {
                pageViewModel = new ViewModelProvider(getParentFragment()).get(PageViewModel.class);
            }
            context = requireActivity().getApplicationContext();
    
        }
    
        @Override
        public View onCreateView(
                @NonNull LayoutInflater inflater, ViewGroup container,
                Bundle savedInstanceState) {
            View root = inflater.inflate(R.layout.fragment_open_map, container, false);
            LocationManager locationManager = (LocationManager) context.getSystemService(LOCATION_SERVICE);
            Location location = locationManager.getLastKnownLocation(LocationManager.GPS_PROVIDER);
            map = root.findViewById(R.id.mapview);
            map.setTileSource(TileSourceFactory.MAPNIK);
            map.setMultiTouchControls(true);
            myPointsMap = new HashMap<>();
            pageViewModel.getMyPoints().observe(getViewLifecycleOwner(), myPointsList -> {
               myPointsMap = 
                   myPointsList.stream().collect(Collectors.toMap(MyPoint::getId, p -> p));
               if (sfpo != null) {
                   map.getOverlays().remove(sfpo);
               }
               sfpo = simpleFastPointOverlayBuilder(myPointsList);
               sfpo.setOnClickListener((points, point) -> {
                    MyPoint mp = myPointsMap
                            .get(Integer.valueOf(((LabelledGeoPoint) points.get(point)).getLabel()));
                    if (marker != null) {
                        map.getOverlays().remove(marker);
                    }
                    marker = constructMarker(mp);
                    map.getOverlays().add(marker);
                });
                map.getOverlays().add(sfpo);
            });
            return root;
        }
    
        private SimpleFastPointOverlay simpleFastPointOverlayBuilder(List<MyPoint> myPointList) {
            List<IGeoPoint> points = new ArrayList<>();
    
            Paint textStyle = new Paint();
            textStyle.setStyle(Paint.Style.FILL);
            textStyle.setColor(Color.parseColor("#111111"));
            textStyle.setTextAlign(Paint.Align.CENTER);
            textStyle.setTextSize(24);
    
            Paint pointStyle = new Paint();
            pointStyle.setStyle(Paint.Style.FILL);
            pointStyle.setColor(Color.rgb(255, 0, 0));
    
            for(MyPoint myPoint: myPointList) {
                points.add(new StyledLabelledGeoPoint(myPoint.getLocationInfo().latitude,
                        myPoint.getLocationInfo().longitude, Integer.toString(myPoint.getId()),
                        pointStyle, textStyle));
            }
    
            SimplePointTheme pointTheme = new SimplePointTheme(points);
    
            SimpleFastPointOverlayOptions opt = SimpleFastPointOverlayOptions.getDefaultStyle()
                    .setSymbol(SimpleFastPointOverlayOptions.Shape.CIRCLE)
                    .setAlgorithm(SimpleFastPointOverlayOptions.RenderingAlgorithm.MAXIMUM_OPTIMIZATION)
                    .setRadius(7).setIsClickable(true).setCellSize(12)
                    .setMinZoomShowLabels(12);
            return new SimpleFastPointOverlay(pointTheme, opt);
        }
    
    
        private Marker constructMarker(MyPoint l) {
            GeoPoint gp = new GeoPoint(l.getLocationInfo().latitude, l.getLocationInfo().longitude);
            Marker marker = new Marker(map);
            marker.setPosition(gp);
            CustomMarkerInfoWindow markerInfoWindow = new CustomMarkerInfoWindow(l, R.layout.marker_info_window, map);
            markerInfoWindow.open(marker, gp, 0, 0);
            marker.setAlpha((float) 0);
            marker.setInfoWindow(markerInfoWindow);
            marker.setInfoWindowAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
            marker.setAnchor(Marker.ANCHOR_CENTER, Marker.ANCHOR_BOTTOM);
            return marker;
        }
    
    
        @Override
        public void onResume() {
            super.onResume();
            map.onResume();
        }
    
        @Override
        public void onPause() {
            super.onPause();
            map.onPause();
        }
    }