【问题标题】:Enlarge the center of an Android gradient drawable放大Android渐变drawable的中心
【发布时间】:2017-03-16 11:45:42
【问题描述】:

我创建了一个Android gradient drawable,顶部和底部是黑色的,中间是透明的:

<shape xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="rectangle" >

    <gradient
        android:startColor="@android:color/black"
        android:centerColor="@android:color/transparent"
        android:endColor="@android:color/black"
        android:angle="90"/>
</shape>

渲染的渐变如下所示:

如您所见,黑色部分扩散到屏幕的大部分区域。我希望黑色只显示在顶部和底部的一小部分。有没有办法让透明中心变大,或者让顶部和底部的黑色条纹变小?

我尝试使用链接的 GradientDrawable 文档中提到的其他一些 XML 属性,但它们似乎都不起作用。

【问题讨论】:

  • 如果无法使用 xml 属性设置一种以上的颜色,您可以尝试扭曲可绘制对象,如果可能的话。否则以编程方式进行
  • @lelloman 我也愿意接受编程建议,尽管只使用 xml 可能会更容易。你有什么想法吗?
  • 我认为你需要一个具有黑色 - 白色 - 黑色但距离不同的 LinearGradient,恐怕 GradientDrawable 不允许你调整颜色的位置,你会吗以编程方式使用自定义 Drawable?
  • @lelloman 感谢您的回复。我将需要尝试您的解决方案。只是指出以防止混淆,中间颜色是透明的,不是白色的。
  • 您可以通过将两个渐变可绘制对象分层来使黑色部分成为视图高度的百分比。查看此要点gist.github.com/luksprog/4ac6e7550564b3823840d4a0943c8dd6 以获取示例(在上面的示例中,黑色部分将分别占据视图高度的 10%)。

标签: android xml gradient android-drawable


【解决方案1】:

对于仅 XML 的解决方案,您可以使用两个单独的 gradient 对象创建一个 layer-list

以下代码创建两个重叠的gradient 对象,并使用centerYcenterColor 来偏移黑色部分。这里centerY属性设置为0.90.1,所以黑色被限制在视图高度的顶部和底部10%。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item>
        <shape>
            <gradient
                android:angle="90"
                android:centerColor="@android:color/transparent"
                android:centerY="0.9"
                android:endColor="@android:color/black"
                android:startColor="@android:color/transparent" />
        </shape>
    </item>

    <item>
        <shape>
            <gradient
                android:angle="90"
                android:centerColor="@android:color/transparent"
                android:centerY="0.1"
                android:endColor="@android:color/transparent"
                android:startColor="@android:color/black" />
        </shape>
    </item>
</layer-list>

对于 API 级别 23 或更高级别,以下解决方案也可以使用 android:height。即使您不知道视图的总高度,只要您知道希望渐变的大小,此解决方案也可以工作。

此代码创建两个单独的渐变,每个渐变的高度为60sp,然后使用android:gravity 将渐变浮动到视图的顶部和底部。

<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
    <item
        android:height="60sp"
        android:gravity="top">
        <shape android:shape="rectangle">
            <gradient
                android:angle="90"
                android:endColor="@android:color/black"
                android:startColor="@android:color/transparent" />
        </shape>
    </item>
    <item
        android:height="65sp"
        android:gravity="bottom">
        <shape android:shape="rectangle">
            <gradient
                android:angle="90"
                android:endColor="@android:color/transparent"
                android:startColor="@android:color/black" />
        </shape>
    </item>
</layer-list>

感谢 @Luksprog 提供代码帮助,感谢 @thenaoh 提出这个想法。

上述解决方案有效,它们是纯 XML,这很好。如果您的渐变带有条纹,您可能需要尝试编程解决方案,如@lelloman's 答案中所示,以创建更平滑的渐变。

【讨论】:

    【解决方案2】:

    这是使用自定义Drawable 完成的方法。您可以根据需要调整LinearGradient,然后使用view.setBackground(new CustomDrawable()); 将其设置为视图的背景。

    public class CustomDrawable extends Drawable {
    
        private Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
        private int[] colors;
        private float[] positions;
    
        public CustomDrawable() {
            paint.setStyle(Paint.Style.FILL);
            this.colors = new int[]{0xff000000, 0xffaaaaaa, 0xffffffff, 0xffaaaaaa, 0xff000000};
            this.positions = new float[]{.0f, .2f, .5f, .8f, 1.f};
        }
    
        @Override
        public void setBounds(int left, int top, int right, int bottom) {
            super.setBounds(left, top, right, bottom);    
    
            LinearGradient linearGradient = new LinearGradient(left, top,left, bottom, colors, positions, Shader.TileMode.CLAMP);
            paint.setShader(linearGradient);
        }
    
        @Override
        public void draw(@NonNull Canvas canvas) {    
            canvas.drawRect(getBounds(), paint);
        }
    
        @Override
        public void setAlpha(@IntRange(from = 0, to = 255) int alpha) {
            paint.setAlpha(alpha);
        }
    
        @Override
        public void setColorFilter(@Nullable ColorFilter colorFilter) {
            paint.setColorFilter(colorFilter);
        }
    
        @Override
        public int getOpacity() {
            return PixelFormat.TRANSPARENT;
        }
    }
    

    【讨论】:

      【解决方案3】:

      有一个解决方案,假设你事先知道你的视图的高度(假设这里是 60dp):

      <layer-list xmlns:android="http://schemas.android.com/apk/res/android">
      <item
          android:bottom="40dp">
          <shape android:shape="rectangle">
              <gradient
                  android:type="linear"
                  android:angle="90"
                  android:startColor="#FFFFFF"
                  android:endColor="#000000"/>
          </shape>
      </item>
      <item
          android:top="20dp"
          android:bottom="20dp"
          android:gravity="center_vertical">
          <shape android:shape="rectangle">
              <solid android:color="#FFFFFF"/>
          </shape>
      </item>
      <item
          android:top="40dp"
          android:gravity="bottom">
          <shape android:shape="rectangle">
              <gradient
                  android:type="linear"
                  android:angle="90"
                  android:startColor="#000000"
                  android:endColor="#FFFFFF"/>
          </shape>
      </item>
      </layer-list>
      

      但如果您事先不知道高度,另一种解决方案是制作自己的自定义视图,如下所示:

      public class MyView extends ImageView
      {
          private Paint paint = null;
      
          public MyView(Context context, AttributeSet attrs)
          {
              super(context, attrs);
              paint = new Paint(Paint.ANTI_ALIAS_FLAG);
          }
      
          @Override
          protected void onDraw(Canvas canvas)
          {
              super.onDraw(canvas);
              paint.setShader(getLinearGradient(0, getHeight()));
              canvas.drawPaint(paint);
          }
      
          private LinearGradient getLinearGradient(float y0, float y1)
          {
              // colors :
              int[] listeColors = new int[3];
              listeColors[0] = 0xFF000000;
              listeColors[1] = 0xFFFFFFFF;
              listeColors[2] = 0xFFFFFFFF;
      
              // positions :
              float[] listPositions = new float[3];
              listPositions[0] = 0;
              listPositions[1] = 0.25F;
              listPositions[2] = 1;
      
              // gradient :
              return new LinearGradient(0, y0, 0, y0 + (y1 - y0) / 2, listeColors, listPositions, Shader.TileMode.MIRROR);
          }
      }
      

      希望对你有帮助。

      【讨论】:

      • 我的view的高度不是一个固定的大小,所以第一个解决方案是行不通的。有没有办法使用百分比解决方案?
      • 我不这么认为,你可以在这里看到:stackoverflow.com/a/6061494/3527024。所以这就是为什么我建议我的第二个选择。
      • 第二个选项看起来不错,但是你可以做同样的事情,而不是子类化 ImageView,子类化 Drawable 并将其设置为你想要的任何视图的背景
      • 我刚刚尝试了您的第一个解决方案,但它没有呈现正确的渐变。黑色蔓延到整个区域。
      猜你喜欢
      • 1970-01-01
      • 2022-06-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多