【问题标题】:How to create a 'transparent circle inside rectangle' shape in XML in Android?如何在 Android 的 XML 中创建“矩形内的透明圆圈”形状?
【发布时间】:2016-08-14 07:20:57
【问题描述】:

我正在尝试在我的应用中创建以下设计。

设计样机

它叠加在主 UI 之上。尝试使用主 UI 顶部的布局创建它,其背景是在 XML 中创建的半透明形状。但是,即使在阅读了多个帖子之后,我也无法弄清楚。

我尝试了以下方法,但没有奏效。创建一个具有 200dp 笔划的环形并将其设置为图像视图的源,然后将 scaletype 设置为 centerCrop,但该形状不会像位图那样缩放。

形状 XML:

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:innerRadius="0dp"
    android:shape="ring"
    android:thicknessRatio="2"
    android:useLevel="false" >

    <solid android:color="@android:color/transparent" />

    <stroke
        android:width="200dp"
        android:color="#80000000" />
</shape>

叠加布局:

<?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">

    <ImageView
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:src="@drawable/onboarding_background"
        android:scaleType="centerCrop"/>

</RelativeLayout>

任何有关如何执行此操作或代码的指示都会非常有帮助。

【问题讨论】:

  • 换句话说,你想要a circular hole cutout at the center of a screen-wide semitransparent rectangle
  • 您可以轻松地为此使用矢量(这是另一种解决方案,以防 xml 不是强制性的)
  • 你想做点半径周围点地图这样的事情对吗? developers.google.com/android/reference/com/google/android/gms/…希望对您有所帮助!它可能与stackoverflow.com/questions/13991301/… 重复
  • 嘿@BobMalooga,感谢您的编辑,我显然无法直接添加图片,因为我需要至少 10 分。我想我应该回答一些问题。
  • @MathieudeBrito,它只是我作为开发人员(即没有设计师)工作,我什至不知道基本的照片,这就是我试图通过使用 xml 来获得的原因。这也减少了一些 apk 大小。

标签: android porter-duff


【解决方案1】:

我最近一直在玩类似的东西,并为你改编了它。 所有的魔法都发生在 onDraw 中:

public class FocusView extends View {
  private Paint mTransparentPaint;
  private Paint mSemiBlackPaint;
  private Path mPath = new Path();

  public FocusView(Context context) {
    super(context);
    initPaints();
  }

  public FocusView(Context context, AttributeSet attrs) {
    super(context, attrs);
    initPaints();
  }

  public FocusView(Context context, AttributeSet attrs, int defStyleAttr) {
    super(context, attrs, defStyleAttr);
    initPaints();
  }

  private void initPaints() {
    mTransparentPaint = new Paint();
    mTransparentPaint.setColor(Color.TRANSPARENT);
    mTransparentPaint.setStrokeWidth(10);

    mSemiBlackPaint = new Paint();
    mSemiBlackPaint.setColor(Color.TRANSPARENT);
    mSemiBlackPaint.setStrokeWidth(10);
  }

  @Override
  protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);

    mPath.reset();

    mPath.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, Path.Direction.CW);
    mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);

    canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, 550, mTransparentPaint);

    canvas.drawPath(mPath, mSemiBlackPaint);
    canvas.clipPath(mPath);
    canvas.drawColor(Color.parseColor("#A6000000"));
  }
 }

这里的诀窍是创建一个Path(透明的圆圈),这样我们就可以将路径的绘制方式设置为“路径外”而不是“路径内”。最后,我们可以简单地将画布剪辑到该路径,并填充黑色。

对您而言,您只需将 Color.BLACK 更改为您的颜色,并更改所需的半径。

编辑: 哦,只需以编程方式添加它: FocusView view = new FocusView(context) your_layout.addView(view)

或通过 XML:

<package_path_to_.FocusView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

EDIT2:我刚刚看到您希望将其用于您的应用程序的入门。 你可以考虑看看https://github.com/iammert/MaterialIntroView然后

【讨论】:

  • 嘿@nicolas,非常感谢这个答案!.. 这个解决方案对我来说完全有效(在对代码进行了一些更改之后)。我可以从答案中编辑您的代码以显示确切的解决方案吗?
  • 对不起,我走了。但是,是的,请随时进行必要的编辑以完全匹配您的问题!
  • 没问题...我编辑了代码。再次感谢您的帮助:)
  • 你好,我怎样才能像这样在中心做一个椭圆形..?
  • 有人可以调整这个以在中心画一个正方形而不是圆形吗?
【解决方案2】:

您可以为此使用PorterDuffXferMode 和自定义视图。

这张图片提供的不同模式的好例子(见 A Out B):AlphaCompositing

这个想法是创建自定义视图,带有不透明的黑色矩形和圆圈。当您应用 PorterDuffXferMode.SRC_OUT 时,它将从矩形中“擦除”圆形,因此您将得到您想要的结果。

在您的自定义视图中,您应该重写 dispatchDraw(Canvas canvas) 方法,并在您的框架上绘制生成的位图。

然后您可以将 MapView 和您的自定义视图放入 FrameLayout 并享受结果。

【讨论】:

    【解决方案3】:

    我遇到了这样一个问题,即代码在 NSimon 的 api lvl 16 上不起作用。 我修复了代码,现在它支持 api 16+。

    public class FocusView extends View {
        private Paint mPaint;
        private Paint mStrokePaint;
        private Path mPath = new Path();
    
        public FocusView(Context context) {
            super(context);
            initPaints();
        }
    
        public FocusView(Context context, AttributeSet attrs) {
            super(context, attrs);
            initPaints();
        }
    
        public FocusView(Context context, AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            initPaints();
        }
    
        private void initPaints() {
            mPaint = new Paint();
            mPaint.setColor(Color.parseColor("#A6000000"));
    
            mStrokePaint = new Paint();
            mStrokePaint.setColor(Color.YELLOW);
            mStrokePaint.setStrokeWidth(2);
            mStrokePaint.setStyle(Paint.Style.STROKE);
    
        }
    
        @Override
        protected void onDraw(Canvas canvas) {
            super.onDraw(canvas);
            mPath.reset();
    
            float radius = 0;
            float strokeWidth = 0;
            if (canvas.getWidth() < canvas.getHeight()) {
                radius = canvas.getWidth() / 2 - 10;
                strokeWidth = (canvas.getHeight() - canvas.getWidth())/2;
            } else {
                radius = canvas.getHeight() / 2 - 10;
                strokeWidth = (canvas.getWidth() - canvas.getHeight())/2;
            }
    
            mPaint.setStrokeWidth(strokeWidth);
    
            mPath.addCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, radius, Path.Direction.CW);
            mPath.setFillType(Path.FillType.INVERSE_EVEN_ODD);
    
            canvas.drawCircle(canvas.getWidth() / 2, canvas.getHeight() / 2, radius, mStrokePaint);
    
            canvas.drawPath(mPath, mPaint);
        }
    }
    

    【讨论】:

    • 如何在中心制作椭圆而不是圆形?
    猜你喜欢
    • 2014-05-04
    • 1970-01-01
    • 2020-10-09
    • 1970-01-01
    • 2014-08-22
    • 2017-03-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多