有没有一种方法可以在MapFragment中实现圆角?

14
我想给地图设置漂亮的圆角,就像下面两个框一样。 但是由于片段本身没有背景属性,所以我无法对地图片段进行设置。 将地图设置在布局内,并将其背景设置为圆形形状也没有帮助,结果如下所示: http://i.stack.imgur.com/LJhP1.jpg 虽然可以合并地图,但这会使它变小,而我想避免这种情况。
编辑: @Ryan 这是新的结果#2: http://i.stack.imgur.com/69D59.jpg 我想这还不错,虽然与其他框的角还有差距,但再花点功夫,我可能会接近那里。但是我没有一个普通的图像编辑器,仍然有一件事让我困扰,那就是“位置”TextView和地图之间的分隔。我能用其他方法将它画出来吗,这样就没有距离了?我是这样做的: http://i.stack.imgur.com/1Qx66.png 好了,我终于搞明白了: http://i.stack.imgur.com/bY4N5.jpg 这是我用来补丁的东西: enter image description here 谢谢。
7个回答

39

我知道这是一个旧帖子,但您可以尝试像这样使用卡片:

<android.support.v7.widget.CardView
    android:layout_width="300dp"
    android:layout_height="350dp"
    android:layout_gravity="center_horizontal|center_vertical"
    android:layout_marginLeft="10dp"
    android:layout_marginRight="10dp"
    android:layout_marginTop="20dp"
    app:cardCornerRadius="12dp"
    app:cardElevation="12dp">

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</android.support.v7.widget.CardView>

在此输入图片描述


今天你可以使用卡片来完成这个任务。当这个问题被提出时,卡片还不存在。非常好的回答。 - Emil Adz

8
我还没有尝试过这种方法,但我会在mapView / mapFragment上放置一个带有圆角和透明中心的视图。也就是说,将mapFragment和圆角视图放入FrameLayout中,并让它们两个填充整个FrameLayout,然后使圆角视图的中间部分透明。为了更加明确,您可以按照以下布局进行操作:
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent" >

<fragment
    xmlns:map="http://schemas.android.com/apk/res-auto"
    android:id="@+id/mapFragment"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    class="com.google.android.gms.maps.MapFragment" />

<LinearLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="@drawable/rounded_background"
    android:orientation="vertical" >
</LinearLayout>

</FrameLayout>

rounded_background是带有圆角和透明中间部分的9-patch图像。例如:rounded_background.9.png 希望能帮到您,
Ryan

你说的“putting a view”是什么意思?是哪种视图?如何使其中间透明? - Emil Adz
我只是制作了一个非常粗糙的9 patch,只是为了让你有个想法,并不打算让你直接使用它;-) 如果你制作一个像样的资源,它会看起来很好。 - Ryan
1
此外,您需要将其用作九宫格图像,并将其重命名为filename.9.png。请参阅此处以获取更多信息:http://radleymarx.com/blog/simple-guide-to-9-patch/。 - Ryan
我尝试着去做,但我想知道是否有其他方法来处理这个问题。你用什么软件来创建这些9-patch图案? - Emil Adz
我从来没有理解如何使用这个工具,是否有其他替代方案? - Emil Adz
它并没有什么特别的功能,只是在您的图像周围添加了一个1像素的边框。请随意使用您喜欢的图像编辑工具。 - Ryan

5
最简单的方法是将地图片段与一个ImageView一起包含在FrameLayout中。 ImageView将在地图片段上方显示一个圆角矩形。在其最简单的形式中,您将看到地图片段位于圆角矩形内部,其角落突出圆角矩形,因为地图视图本身不是圆角的。为了克服这种视觉奇怪现象,只需在地图片段上应用layout_margin值即可。该值应等于矩形边框宽度。
   <FrameLayout
    android:id="@+id/map_container"
    android:layout_width="wrap_content"
    android:layout_height="340dp" >

    <fragment
        android:id="@+id/map"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_margin="3dp"
        android:name="com.google.android.gms.maps.SupportMapFragment"/>

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/map_bg_box" />

</FrameLayout>

矩形可绘制对象定义为以下XML形状:
<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">

    <stroke android:width="3dp"
    android:color="#ff000000" />

    <corners android:bottomRightRadius="7dp" android:bottomLeftRadius="7dp"
    android:topLeftRadius="7dp" android:topRightRadius="7dp"/>

</shape>

注意矩形的描边宽度为3dp,这与我们应用于地图片段的layout_margin属性完全相同。结果是一个漂亮的圆角地图片段,如下面的截图所示。

这对我没有用。我尝试了一切,但它没有起作用。 - KinGPinG
1
你按照这里描述的解决方案得到了什么结果? - Nouman Hanif
1
地图的角落重叠在黑色圆形上:S,地图超出了形状。 - KinGPinG
1
@KinGPinG,你确定按照正确的顺序放置了形状吗? - Muhammed Refaat

2

将地图片段放入此布局中:

package com.example.yourpackage;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.widget.RelativeLayout;

/**
 * Just extend any Layout you like/need
 */
public class RoundedLayout extends RelativeLayout {

private Path mPathCorners = new Path();
private Path mPathCircle = new Path();
private float mCornerRadius;

/**
 * border path
 */
private Path mPathCornersBorder = new Path();
private Path mPathCircleBorder = new Path();
private int mBorderWidth = 0;
private int mBorderHalf;
private boolean mShowBorder = false;
private int mBorderColor = 0xFFFF7700;

private float mDensity = 1.0f;

/**
 * Rounded corners or circle shape
 */
private boolean mIsCircleShape = false;

private Paint mPaint = new Paint();

private float dpFromPx(final float px) {
    return px / mDensity;
}

private float pxFromDp(final float dp) {
    return dp * mDensity;
}

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

public RoundedLayout(Context context, AttributeSet attrs) {
    this(context, attrs, 0);
}

public RoundedLayout(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    mDensity = getResources().getDisplayMetrics().density;
    // just a default for corner radius
    mCornerRadius = pxFromDp(25f);

    mPaint.setAntiAlias(true);
    mPaint.setStyle(Paint.Style.STROKE);
    mPaint.setColor(mBorderColor);
    setBorderWidth(Math.round(pxFromDp(2f)));
}

/**
 * Switch to circle or rectangle shape
 *
 * @param useCircle
 */
public void setShapeCircle(boolean useCircle) {
    mIsCircleShape = useCircle;
    invalidate();
}

/**
 * change corner radius
 *
 * @param radius
 */
public void setCornerRadius(int radius) {
    mCornerRadius = radius;
    invalidate();
}

public void showBorder(boolean show) {
    mShowBorder = show;
    invalidate();
}

public void setBorderWidth(int width) {
    mBorderWidth = width;
    mBorderHalf = Math.round(mBorderWidth / 2);
    if (mBorderHalf == 0) {
        mBorderHalf = 1;
    }

    mPaint.setStrokeWidth(mBorderWidth);
    updateCircleBorder();
    updateRectangleBorder();
    invalidate();
}

public void setBorderColor(int color) {
    mBorderColor = color;
    mPaint.setColor(color);
    invalidate();
}

// helper reusable vars, just IGNORE
private float halfWidth, halfHeight, centerX, centerY;
private RectF rect = new RectF(0, 0, 0, 0);
private RectF rectBorder = new RectF(0, 0, 0, 0);

@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
    super.onSizeChanged(w, h, oldw, oldh);

    // just calculate both shapes, is not heavy

    // rounded corners path
    rect.left = 0;
    rect.top = 0;
    rect.right = w;
    rect.bottom = h;
    mPathCorners.reset();
    mPathCorners.addRoundRect(rect, mCornerRadius, mCornerRadius, Path.Direction.CW);
    mPathCorners.close();

    // circle path
    halfWidth = w / 2f;
    halfHeight = h / 2f;
    centerX = halfWidth;
    centerY = halfHeight;
    mPathCircle.reset();
    mPathCircle.addCircle(centerX, centerY, Math.min(halfWidth, halfHeight), Path.Direction.CW);
    mPathCircle.close();

    updateRectangleBorder();
    updateCircleBorder();
}

// helper reusable var, just IGNORE
private int save;

@Override
protected void dispatchDraw(Canvas canvas) {
    save = canvas.save();
    canvas.clipPath(mIsCircleShape ? mPathCircle : mPathCorners);
    super.dispatchDraw(canvas);
    canvas.restoreToCount(save);

    if (mShowBorder) {
        canvas.drawPath(mIsCircleShape ? mPathCircleBorder : mPathCornersBorder, mPaint);
    }
}

private void updateCircleBorder() {
    // border path for circle
    mPathCircleBorder.reset();
    mPathCircleBorder.addCircle(centerX, centerY, Math.min(halfWidth - mBorderHalf,
            halfHeight - mBorderHalf), Path.Direction.CW);
    mPathCircleBorder.close();
}

private void updateRectangleBorder() {
    // border path for rectangle
    rectBorder.left = rect.left + mBorderHalf;
    rectBorder.top = rect.top + mBorderHalf;
    rectBorder.right = rect.right - mBorderHalf;
    rectBorder.bottom = rect.bottom - mBorderHalf;
    mPathCornersBorder.reset();
    mPathCornersBorder.addRoundRect(rectBorder, mCornerRadius - mBorderHalf, mCornerRadius -
            mBorderHalf, Path.Direction.CW);
    mPathCornersBorder.close();
}
}

布局将会是这样的:
<com.example.yourpackage.RoundedLayout
    android:id="@+id/maplayout"
    android:layout_width="match_parent"
    android:layout_height="200dp"
    android:layout_margin="20dp">

    <fragment
        android:id="@+id/map"
        android:name="com.google.android.gms.maps.SupportMapFragment"
        android:layout_width="match_parent"
        android:layout_height="200dp"
        tools:context="com.example.yourpackage.MapsMarkerActivity"/>
</com.example.yourpackage.RoundedLayout>

在代码中,可以像这样创建带边框的圆形形状:
    RoundedLayout rl = (RoundedLayout) findViewById(R.id.maplayout);
    rl.setShapeCircle(true);
    rl.showBorder(true);
    rl.setBorderWidth(2);

这种布局可以用来调整任何视图。

令人难以置信的是,谷歌无法为其Android API制作出称职(可用)的完整演示。


0

在@Nouman_Hanif的帖子之后,我得到了一个看起来相当不错的解决方案。

map_rounded_corner_overlay.xml:

<?xml version="1.0" encoding="UTF-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
  <stroke android:width="1dp"
          android:color="@color/white" />
  <corners android:radius="<your_desired_view_corner_radius>"/>
</shape>

我的地图 XML 文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
                android:layout_width="match_parent"
                android:layout_height="match_parent">
  <fragment
    android:id="@+id/map"
    android:name="com.google.android.gms.maps.SupportMapFragment"
    android:layout_margin="1dp"
    android:layout_width="match_parent"
    android:layout_height="match_parent" />
  <ImageView
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:src="@drawable/map_rounded_corner_overlay" />
</RelativeLayout>

0

如果你只想针对API 21(棒棒糖)及以上版本进行开发


这是可能的最简单的方法。

parentView.setClipToOutline(true);

结果

enter image description here


1
什么是“parentView”?我尝试将setClipToOutline(true)设置为实际的MapFragment,但对我来说不起作用... - EZDsIt
parentView 是 mapFragment 所在的视图。它是包含 mapFragment 的视图。 - Michael
对我没用...我用一个带有圆角背景的LinearLayout包装了地图片段,并调用了setClipToOutline(true);正如你建议的那样。也许这与我正在使用的主题'Theme.Translucent.NoTitleBar.Fullscreen'有关...? - EZDsIt

0

对于其他想要解决这个问题的人,我使用了GoogleMap.snapshot并使用以下Stack Overflow答案操纵位图结果来解决它: 如何制作带有圆角的ImageView?

请注意,仅当您将拥有不需要交互的静态地图时,此方法才有效。

确保在地图加载后再进行快照。

我更新了ImageView帮助程序代码以使用路径绘制,以支持仅圆角某些角。例如,如果您只想圆角处理2个角。

您只需要使用浮点数数组的路径round rect函数即可。

我显示进度条,直到从GoogleMap加载侦听器获得回调,然后我才会获取快照。

如果您过早地获取快照,则会出现无法创建0宽度和高度的位图错误。

希望这可以帮助寻找静态地图快照中圆角或其他奇怪形状的人。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接