حذف نشانگر

مستندات جامع اندروید

نسخه 1.0.3

این بخش از پروژه عملکرد حذف و اضافه کردن نشانگر (پین) را بیان میکند

فهرست مطالب این صفحه

در این پروژه نشانگرها با لمس طولانی ایجاد می‌شوند و پس از آن با لمس هر یک از نشانگرها منویی برای تایید حذف نشانگر به صورت یک bottom sheet پدیدار می‌شود

remove_marker_bottom_sheet.xml :

این فایل طراحی منوی bottom sheet است که برای تایید حذف نمایش داده می‌شود.

            <?xml version="1.0" encoding="utf-8"?>
<android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_marginStart="8dp"
    android:layout_marginEnd="8dp"
    android:clickable="true"
    android:fitsSystemWindows="true"
    android:focusable="true"
    android:layoutDirection="ltr"
    app:behavior_hideable="false"
    app:behavior_peekHeight="0dp"
    app:cardCornerRadius="8dp"
    app:cardElevation="8dp"
    app:layout_behavior="android.support.design.widget.BottomSheetBehavior">

    <android.support.constraint.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content">

        <Button
            android:id="@+id/remove_marker"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_marginStart="25dp"
            android:layout_marginTop="10dp"
            android:layout_marginBottom="15dp"
            android:background="@android:color/holo_red_dark"
            android:text="حذف"
            android:textColor="@color/textPrimaryColorInverse"
            android:textSize="15sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_bias="1.0" />

        <TextView
            android:id="@+id/marker_id"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:layout_margin="25dp"
            android:fontFamily="@font/iran_sans_bold"
            android:text="از حذف پین مطمئن هستید؟"
            android:textSize="15sp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toEndOf="@+id/remove_marker"
            app:layout_constraintTop_toTopOf="parent" />

    </android.support.constraint.ConstraintLayout>

</android.support.v7.widget.CardView>
        

activity_remove_marker.xml :

این فایل فقط شامل نقشه و یک include از فایل قبل (bottom sheet) می‌باشد

            <?xml version="1.0" encoding="utf-8"?>
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".activity.RemoveMarker">

    <org.neshan.mapsdk.MapView
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />

    <include
        android:id="@+id/remove_marker_bottom_sheet_include"
        layout="@layout/remove_marker_bottom_sheet" />

</android.support.design.widget.CoordinatorLayout>
        

RemoveMarker.java :

ابتدا در متد initViews تمام المان های موجود را تعریف میکنیم همچنین در این جا از متد BottomSheetCallback برای bottom sheet استفاده میکنیم. در این متد تعریف میکنیم که اگر کاربر bottom sheet را به صورت دستی collapse کرد ، نشانگر انتخاب شده نیز deselect شود

            private void initViews() {
        map = findViewById(R.id.map);
        marker_id = findViewById(R.id.marker_id);
        remove_marker = findViewById(R.id.remove_marker);
        // bottom sheet include tag and behavior
        remove_marker_bottom_sheet = findViewById(R.id.remove_marker_bottom_sheet_include);
        bottomSheetBehavior = BottomSheetBehavior.from(remove_marker_bottom_sheet);
        remove_marker.setVisibility(View.GONE);
        marker_id.setText(Html.fromHtml(firstTipString));
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);

        // bottom sheet callback deselect marker for when bottom sheet collapsed manually
        bottomSheetBehavior.setBottomSheetCallback(new BottomSheetBehavior.BottomSheetCallback() {
            @Override
            public void onStateChanged(@NonNull View bottomSheet, int newState) {
                if (newState == BottomSheetBehavior.STATE_COLLAPSED && selectedMarker != null) {
                    deselectMarker(selectedMarker);
                }
            }

            @Override
            public void onSlide(@NonNull View bottomSheet, float slideOffset) {
            }
        });
    }
        

متد initMap و addMarker و changeMarkerToBlue درست همانند متدی به همین نام در بخش اضافه‌کردن نشانگر کار میکنند

متد changeMarkerToRed نیز دقیقا مشابه متد changeMarkerToBlue کار میکند با این تفاوت که رنگ نشانگر را به رنگ قرمز تغییر میدهد

                 private void changeMarkerToRed(Marker blueMarker){
        // create new marker style
        MarkerStyleCreator markStCr = new MarkerStyleCreator();
        markStCr.setSize(30f);
        // Setting a new bitmap as marker
        markStCr.setBitmap(BitmapUtils.createBitmapFromAndroidBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.ic_marker)));
        markStCr.setAnimationStyle(animSt);
        MarkerStyle redMarkSt = markStCr.buildStyle();

        // changing marker style using setStyle
        blueMarker.setStyle(redMarkSt);
    }
        

حال به بررسی متد initLayoutReferences می‌پردازیم

در این متد پس از فراخوانی متدهای initViews و initMap برای map یک setOnMapLongClickListener تعریف می‌شود برای تشخیص لمس طولانی بر روی نقشه. با لمس طولانی ابتدا وضعیت bottomSheet بررسی می شود تا در صورتی که باز ( Expanded ) است، اگر نشانه ای انتخاب شده از حالت انتخاب خارج شود و bottomSheet نیز جمع ( collapse ) شود. و اگر باز نیست یک نشانه جدید بر روی نقشه اضافه شود.

از آنجایی که در قدم اول که کاربر وارد صفحه RemoveMarker.java می‌شود، یک راهنمایی برای او نمایان است برای اینکه بخواهیم با لمس طولانی اول یک نشانگر جدید ایجاد شود و سپس راهنمایی دوم نمایان شود باید این موضوع را بررسی کنیم. به شرط‌های داخل onMapLongClick توجه کنید

            map.setOnMapLongClickListener(new MapView.OnMapLongClickListener() {
            @Override
            public void onMapLongClick(LatLng var1) {
                // check the bottom sheet expanded or collapsed
                if (bottomSheetBehavior.getState() == BottomSheetBehavior.STATE_EXPANDED) {

                    if (selectedMarker == null) {
                        // if bottom sheet is expanded and no marker selected second tip is going up (for just one time)
                        collapseBottomSheet();
                        // delay for collapsing then expanding bottom sheet
                        remove_marker_bottom_sheet.postDelayed(new Runnable() {
                            @Override
                            public void run() {
                                expandBottomSheet();
                            }
                        }, 200);
                        remove_marker_bottom_sheet.post(new Runnable() {
                            @Override
                            public void run() {
                                marker_id.setText(Html.fromHtml(secondTipString));
                            }
                        });
                    } else {
                        // if bottom sheet is expanded and any marker selected deselect that marker by long tap
                        deselectMarker(selectedMarker);
                    }
                }
                // addMarker adds a marker (pretty self explanatory :D) to the clicked location
                addMarker(var1, "Marker "+ ++markerIndex);
            }
        });
        

همچنین یک setOnMapClickListener برای تشخیص کلیک بر روی نقشه و deselect کردن نشانه انتخاب شده تعریف شده است.

            map.setOnMapClickListener(new MapView.OnMapClickListener() {
            @Override
            public void onMapClick(LatLng var1) {
                if (selectedMarker != null) {
                    // deselect marker when tap on map and a marker is selected
                    deselectMarker(selectedMarker);
                }
            }
        });
        

و با اضافه کردن یک setOnMarkerClickListener نیز این امکان ایجاد می شود تا با تشخصی کلیک بر روی نشانه های اضافه شده در نقشه، اگر نشانه انتخاب شده است، از انتخاب خارج شود و اگر انتخاب نشده، انتخاب شود.

            // marker listener for select and deselect markers
        map.setOnMarkerClickListener(new MapView.OnMarkerClickListener() {
            @Override
            public void OnMarkerClicked(Marker marker) {
                if (selectedMarker != null) {
                    // deselect marker when tap on a marker and a marker is selected
                    deselectMarker(selectedMarker);
                } else {
                    // select marker when tap on a marker
                    selectMarker(marker);
                    remove_marker_bottom_sheet.post(new Runnable() {
                        @Override
                        public void run() {
                            marker_id.setText("از حدف پین " + marker.getTitle() + " اطمینان دارید؟");
                            remove_marker.setVisibility(View.VISIBLE);
                        }
                    });
                }
            }
        });
        

و در آخر یک رویداد کلیک هم بر روی کلید remove_marker تعریف شده تا با زدن آن، نشانه انتخاب شده به کمک متد removeMarker از روی نقشه حذف شود.

            // remove marker and deselect that marker
        remove_marker.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (selectedMarker != null) {
                    map.removeMarker(selectedMarker);
                    deselectMarker(selectedMarker);
                }
            }
        });
        

در صورتی که راهنمایی اول نمایان باشد با لمس طولانی یک نشانگر جدید ایجاد شده و سپس راهنمایی دوم پدیدار می‌شود و در صورتی که راهنمایی نمایان نباشد فقط یک نشانگر جدید ایجاد می‌شود. همچنین اگر یک نشانگر از قبل انتخاب شده باشد با لمس روی نقشه آن نشانگر deselect می‌شود

در متد deselectMarker همانطور که از نامش پیداست یک نشانگر را در ورودی دریافت میکند و آن را با تغییر رنگ و بستن bottom sheet و مساوی قرار دادن متغیر selectedMarker با null آن نشانگر را deselect (لغو انتخاب) میکند

            private void deselectMarker(final Marker deselectMarker) {
        collapseBottomSheet();
        changeMarkerToBlue(deselectMarker);
        selectedMarker = null;
    }
        

متد selectMarker نیز همانند متند قبل یک نشانگر را انتخاب می‌کند. این عملیات شامل نمایان شدن bottom sheet ، تغییر رنگ نشانگر و ذخیره نشانگر در متغیر selectedMarker می‌شود

             private void selectMarker(final Marker selectMarker) {
        expandBottomSheet();
        changeMarkerToRed(selectMarker);
        selectedMarker = selectMarker;
    }
        

توابع collapseBottomSheet و expandBottomSheet به ترتیب کار بسته شدن و نمایان شده bottom sheet را بر عده دارند

            private void collapseBottomSheet() {
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_COLLAPSED);
    }

    private void expandBottomSheet() {
        bottomSheetBehavior.setState(BottomSheetBehavior.STATE_EXPANDED);
    }
        

در انتها در متد onBackPressed تغییری به این صورت ایجاد میکنیم که اگر یک نشانگر انتخاب شده باشد، با فشردن دکمه back از صفحه خارج نشویم و فقط bottom sheet ناپدید شود

            @Override
    public void onBackPressed() {
        if (selectedMarker != null) {
            deselectMarker(selectedMarker);
        } else {
            super.onBackPressed();
        }
    }