Search code examples
androidkotlinsupportmapfragment

Making a Circular SupportMapFragment


On Android API 28, using Kotlin, I'm trying to make my SupportMapFragment circular so I can make it have animation around it, however, when I try to turn clipToOutline to true, it still stays a square. How can I conform this into a circle? Thank you!

// Preview of Screenshot

enter image description here

// XML

<androidx.fragment.app.FragmentContainerView
    android:id="@+id/customerMapView"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_width="200dp"
    android:layout_height="200dp"
    android:layout_marginTop="16dp"
    android:background="@drawable/circle_mask"
    android:clipToOutline="true"
    android:contentDescription="@string/customer_map_view"
    app:layout_constraintEnd_toEndOf="@id/pulsatingCircle"
    app:layout_constraintStart_toStartOf="@id/pulsatingCircle"
    app:layout_constraintTop_toTopOf="@id/pulsatingCircle" />

// circle_mask

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item android:drawable="@android:color/transparent" />
    <item>
        <shape android:shape="oval">
            <size
                android:width="300dp"
                android:height="300dp" />
        </shape>
    </item>
</layer-list>

// Kotlin Code

private fun initMap() {
    val mapView = supportFragmentManager.findFragmentById(R.id.customerMapView) as SupportMapFragment

    mapView.view?.outlineProvider = ViewOutlineProvider.BACKGROUND
    mapView.view?.clipToOutline = true
}

I tried setting clipToOutline to true in the xml and Kotlin files, but in the xml, I need to be on API 32.


Solution

  • You can use CardView for that.

    As you have fixed width and height, you can pass a specific corner radius to make it look like circle and you're done!

    <com.google.android.material.card.MaterialCardView
            android:id="@+id/mapCardLayout"
            android:layout_width="200dp"
            android:layout_height="200dp"
            app:cardBackgroundColor="@android:color/transparent"
            app:cardCornerRadius="100dp"
            app:cardElevation="0dp">
    
            <androidx.fragment.app.FragmentContainerView
                android:id="@+id/customerMapView"
                android:name="com.google.android.gms.maps.SupportMapFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </com.google.android.material.card.MaterialCardView>
    

    If you don't have a specific width or height, then you can go with the custom view with the same width height for proper circle like this,

    import android.content.Context
    import android.util.AttributeSet
    import com.google.android.material.card.MaterialCardView
    
    class CircleCardView : MaterialCardView {
        constructor(context: Context?) : super(context)
        constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
            context,
            attrs,
            defStyleAttr
        )
    
        override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
            super.onMeasure(widthMeasureSpec, widthMeasureSpec)
        }
    }
    

    For circle appearance, make a custom style attribute and use it with the cardview like this,

    In the style.xml,

    <style name="CustomCardCornerStyle" parent="@style/Widget.MaterialComponents.CardView">
            <item name="shapeAppearanceOverlay">@style/ShapeAppearanceOverlay_card_corners</item>
        </style>
        
        <style name="ShapeAppearanceOverlay_card_corners" parent="">
            <item name="cornerFamily">rounded</item>
            <item name="cornerSize">50%</item>
        </style>
    

    In your layout.xml,

    <com.demo.motiondemo.CircleCardView
            android:id="@+id/mapCardLayout"
            style="@style/CustomCardCornerStyle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            app:cardBackgroundColor="@android:color/transparent"
            app:cardElevation="0dp">
    
            <androidx.fragment.app.FragmentContainerView
                android:id="@+id/customerMapView"
                android:name="com.google.android.gms.maps.SupportMapFragment"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </com.demo.motiondemo.CircleCardView>