【问题标题】:Android: how to clip only top rounded cornersAndroid:如何仅剪切顶部圆角
【发布时间】:2019-09-21 08:50:33
【问题描述】:

我正在创建一个内部带有 FrameLayout 的 ScrollView。我想设计它,以便在 ScrollView 上只有顶角是圆角的。我创建了一个可绘制的形状,如下所示

<shape>
    <solid android:color="@color/white"/>
    <corners
        android:bottomLeftRadius="0dp"
        android:bottomRightRadius="0dp"
        android:topLeftRadius="16dp"
        android:topRightRadius="16dp"/>
    <padding android:padding="0dp"/>
</shape>

然后我在 ScrollView 上设置了以下内容

 scrollView.setOutlineProvider(ViewOutlineProvider.BACKGROUND);
 scrollView.setClipToOutline(true);

当我尝试滚动时,FrameLayout 中的元素最终会突出到我的滚动视图的轮廓中

Excuse the drawing, but what i'm looking to achieve

但是,如果我改为创建这样的形状

<shape>
    <solid android:color="@color/white"/>
    <corners
        android:radius="16dp"/>
    <padding android:padding="0dp"/>
</shape> 

它剪辑得很好。

如果我只希望顶部被拐角,我将如何剪辑它。

【问题讨论】:

    标签: android clip


    【解决方案1】:

    这是@Jankers 答案的 Kotlin 变体,也是对@Tony 问题的回答。说明如何仅放置一个圆角或两个相邻的圆角。

      fun setCorners() {
            
            val outlineProvider = object : ViewOutlineProvider() {
                override fun getOutline(view: View, outline: Outline) {
    
                    val left = 0
                    val top = 0;
                    val right = view.width
                    val bottom = view.height
                    val cornerRadiusDP = 16f
                    val cornerRadius = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, resources.displayMetrics).toInt()
    
                    // all corners
                    outline.setRoundRect(left, top, right, bottom, cornerRadius.toFloat())
    
                    /* top corners
                    outline.setRoundRect(left, top, right, bottom+cornerRadius, cornerRadius.toFloat())*/
    
                    /* bottom corners
                    outline.setRoundRect(left, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
    
                    /* left corners
                    outline.setRoundRect(left, top, right + cornerRadius, bottom, cornerRadius.toFloat())*/
    
                    /* right corners
                    outline.setRoundRect(left - cornerRadius, top, right, bottom, cornerRadius.toFloat())*/
    
                    /* top left corner
                    outline.setRoundRect(left , top, right+ cornerRadius, bottom + cornerRadius, cornerRadius.toFloat())*/
    
                    /* top right corner
                    outline.setRoundRect(left - cornerRadius , top, right, bottom + cornerRadius, cornerRadius.toFloat())*/
    
                    /* bottom left corner
                    outline.setRoundRect(left, top - cornerRadius, right + cornerRadius, bottom, cornerRadius.toFloat())*/
    
                    /* bottom right corner
                    outline.setRoundRect(left - cornerRadius, top - cornerRadius, right, bottom, cornerRadius.toFloat())*/
    
                }
            }
    
            myView.outlineProvider = outlineProvider
            myView.clipToOutline = true
    
        }
    

    【讨论】:

      【解决方案2】:

      我已经设法通过创建自定义 ViewOutlineProvider 并使用它而不是背景值来实现此功能

      ViewOutlineProvider mViewOutlineProvider = new ViewOutlineProvider() {
          @Override
          public void getOutline(final View view, final Outline outline) {
              float cornerRadiusDP = 16f;
              float cornerRadius = TypedValue.applyDimension( TypedValue.COMPLEX_UNIT_DIP, cornerRadiusDP, getResources().getDisplayMetrics());
                  outline.setRoundRect(0, 0, view.getWidth(), (int)(view.getHeight() + cornerRadius), cornerRadius);
              }
      };
      scrollView.setOutlineProvider(mViewOutlineProvider);
      scrollView.setClipToOutline(true);
      

      【讨论】:

      • 非常有用的答案。为我工作。谢谢。
      • 只对一个角落怎么做
      • @Tony 我不是 100% 确定,但也许可以尝试查看 outline.setRoundRect 方法,看看是否可以使用它来选择一个角
      • 原理是什么
      【解决方案3】:

      我从@Jankers 和@Dragan 那里得到了解决方案并对其进行了浓缩,并添加了数据绑定,以便可以从xml 中完成。

      注意:带轮廓的剪裁不支持角落不同 尺寸!

      OutlineProviders:

      class RoundedCornersOutlineProvider(
          val radius: Float? = null,
          val topLeft: Float? = null,
          val topRight: Float? = null,
          val bottomLeft: Float? = null,
          val bottomRight: Float? = null,
      ) : ViewOutlineProvider() {
      
          private val topCorners = topLeft != null && topLeft == topRight
          private val rightCorners = topRight != null && topRight == bottomRight
          private val bottomCorners = bottomLeft != null && bottomLeft == bottomRight
          private val leftCorners = topLeft != null && topLeft == bottomLeft
          private val topLeftCorner = topLeft != null
          private val topRightCorner = topRight != null
          private val bottomRightCorner = bottomRight != null
          private val bottomLeftCorner = bottomLeft != null
      
          override fun getOutline(view: View, outline: Outline) {
              val left = 0
              val top = 0
              val right = view.width
              val bottom = view.height
      
              if (radius != null) {
                  val cornerRadius = radius //.typedValue(resources).toFloat()
                  outline.setRoundRect(left, top, right, bottom, cornerRadius)
              } else {
                  val cornerRadius = topLeft ?: topRight ?: bottomLeft ?: bottomRight ?: 0F
      
                  when {
                      topCorners -> outline.setRoundRect(left, top, right, bottom + cornerRadius.toInt(), cornerRadius)
                      bottomCorners -> outline.setRoundRect(left, top - cornerRadius.toInt(), right, bottom, cornerRadius)
                      leftCorners -> outline.setRoundRect(left, top, right + cornerRadius.toInt(), bottom, cornerRadius)
                      rightCorners -> outline.setRoundRect(left - cornerRadius.toInt(), top, right, bottom, cornerRadius)
                      topLeftCorner -> outline.setRoundRect(
                          left, top, right + cornerRadius.toInt(), bottom + cornerRadius.toInt(), cornerRadius
                      )
                      bottomLeftCorner -> outline.setRoundRect(
                          left, top - cornerRadius.toInt(), right + cornerRadius.toInt(), bottom, cornerRadius
                      )
                      topRightCorner -> outline.setRoundRect(
                          left - cornerRadius.toInt(), top, right, bottom + cornerRadius.toInt(), cornerRadius
                      )
                      bottomRightCorner -> outline.setRoundRect(
                          left - cornerRadius.toInt(), top - cornerRadius.toInt(), right, bottom, cornerRadius
                      )
                  }
              }
          }
      }
      
      class CircleOutlineProvider : ViewOutlineProvider() {
          override fun getOutline(view: View, outline: Outline) {
              val size = view.run { min(width, height) }
              outline.setRoundRect(0, 0, size, size, (size).toFloat())
          }
      }
      

      Data Binding (@BindingAdapter):

      @BindingAdapter("clipCircle")
      fun View.bindClipCircle(clipCircle: Boolean?) {
          outlineProvider = CircleOutlineProvider()
          clipToOutline = true
      }
      
      @BindingAdapter("clipRadius", "clipTopLeft", "clipTopRight", "clipBottomLeft", "clipBottomRight", requireAll = false)
      fun View.bindClipCorners(radius: Float?, topLeft: Float?, topRight: Float?, bottomLeft: Float?, bottomRight: Float?) {
          this.outlineProvider = RoundedCornersOutlineProvider(radius, topLeft, topRight, bottomLeft, bottomRight)
          this.clipToOutline = true
      }
      

      Clipping in xml

      <androidx.constraintlayout.widget.ConstraintLayout
          clipCircle="@{@bool/const_true}"
          ...
      
      <ImageView
          clipBottomLeft="@{@dimen/green_tab_corner_radius}"
          clipBottomRight="@{@dimen/green_tab_corner_radius}"
          ...
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-05-06
        • 2012-02-14
        • 2019-04-07
        • 2020-08-28
        • 1970-01-01
        • 1970-01-01
        • 2012-01-27
        • 2023-02-03
        相关资源
        最近更新 更多