以编程方式创建一个带有渐变笔划的按钮?

时间:2018-05-16 06:11:56

标签: android android-layout android-button

我正在创建一个没有填充但是渐变笔划的按钮。作为参考,这是我追求的最终结果:

enter image description here

我想知道如何使用渐变笔划创建这样一个按钮,而不是以编程方式填充。我查看了GradientDrawable类和其中的setStroke()方法。似乎没有人允许这样做。有没有办法以编程方式执行此操作或根本不可能执行此操作?

3 个答案:

答案 0 :(得分:2)

我为你尝试过一些东西.. 使用mRect.set设置路径,mPath.addRoundRect添加矩形。使用setShader代替strock link

Drawable class:

public class CustomDrawable extends Drawable {
Paint mPaint;
int startColor, endColor, mBorderWidth, mBorderRadius;
RectF mRect;
Path mPath;

public CustomDrawable(int startColor, int endColor, int borderWidth, int borderRadius) {
    mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
    mPaint.setStyle(Paint.Style.FILL);

    mPath = new Path();
    mPath.setFillType(Path.FillType.EVEN_ODD);

    mRect = new RectF();
    this.startColor = startColor;
    this.endColor = endColor;

    mBorderWidth = borderWidth;
    mBorderRadius = borderRadius;
}

@Override
protected void onBoundsChange(Rect bounds) {
    super.onBoundsChange(bounds);
    mPath.reset();

    // out rect
    mRect.set(bounds.left + mBorderWidth, bounds.top + mBorderWidth, bounds.right - mBorderWidth, bounds.bottom - mBorderWidth);
    mPath.addRoundRect(mRect, mBorderRadius, mBorderRadius, Path.Direction.CW);

    // inner rect
    mRect.set(bounds.left + 20, bounds.top + 20, bounds.right - 20, bounds.bottom - 20);
    mPath.addRoundRect(mRect, mBorderRadius, mBorderRadius, Path.Direction.CW);
}

@Override
public void draw(@NonNull Canvas canvas) {
    // kind of strock 
    mPaint.setShader(new LinearGradient(0, 0, 0, 100, startColor, endColor, Shader.TileMode.MIRROR));
    canvas.drawPath(mPath, mPaint);
}
@Override
public void setAlpha(int alpha) { mPaint.setAlpha(alpha);}
@Override
public void setColorFilter(@Nullable ColorFilter colorFilter) {mPaint.setColorFilter(colorFilter);}
@Override
public int getOpacity() {return PixelFormat.TRANSLUCENT;}
}

主要:

Button but = ((Button)findViewById(R.id.but));
but.setBackground(new CustomDrawable(Color.parseColor("#FD659B"),
       Color.parseColor("#F76E63"),
       but.getPaddingLeft(), 100));

布局:

<Button
    android:id="@+id/but"
    android:layout_width="300dp"
    android:layout_height="80dp"
    android:background="@android:color/transparent"
    android:layout_centerInParent="true"
    android:text="Signin"/>

答案 1 :(得分:1)

这是@ lamat8贡献的又一步:

import android.graphics.*
import android.graphics.Paint.ANTI_ALIAS_FLAG
import android.graphics.Path.FillType
import android.graphics.drawable.Drawable
import androidx.annotation.NonNull
import java.lang.RuntimeException


class GradientDrawable(
    private var strokeStartColor: Int,
    private var strokeEndColor: Int,
    private var fillStartColor: Int,
    private var fillEndColor: Int,
    private var strokeWidth: Float,
    private var radius: Float,
    private var strokeGradientDirection: Direction,
    private var fillGradientDirection: Direction
) : Drawable() {

    enum class Direction {
        LEFT_RIGHT,
        TOP_BOTTOM,
        RIGHT_LEFT,
        BOTTOM_TOP,
        TL_BR,
        TR_BL,
        BR_TL,
        BL_TR
    }

    private val strokePaint: Paint = Paint(ANTI_ALIAS_FLAG)
    private val fillPaint: Paint = Paint(ANTI_ALIAS_FLAG)
    private val strokeOuterRect = RectF()
    private val fillRect = RectF()
    private val path = Path()

    init {
        strokePaint.style = Paint.Style.FILL
        path.fillType = FillType.EVEN_ODD
    }

    override fun onBoundsChange(bounds: Rect) {
        super.onBoundsChange(bounds)

        path.reset()

        strokeOuterRect.set(bounds)
        fillRect.set(
            bounds.left + strokeWidth,
            bounds.top + strokeWidth,
            bounds.right - strokeWidth,
            bounds.bottom - strokeWidth
        )

        path.addRoundRect(
            strokeOuterRect,
            radius,
            radius,
            Path.Direction.CW
        )

        path.addRoundRect(
            fillRect,
            radius,
            radius,
            Path.Direction.CW
        )
    }

    override fun draw(@NonNull canvas: Canvas) {
        var x0: Float
        var y0: Float
        var x1: Float
        var y1: Float

        // drawing the stroke

        when (strokeGradientDirection) {
            Direction.LEFT_RIGHT -> {
                x0 = strokeOuterRect.left
                y0 = strokeOuterRect.centerY()
                x1 = strokeOuterRect.right
                y1 = strokeOuterRect.centerY()
            }
            Direction.TOP_BOTTOM -> {
                x0 = strokeOuterRect.centerX()
                y0 = strokeOuterRect.top
                x1 = strokeOuterRect.centerX()
                y1 = strokeOuterRect.bottom
            }
            Direction.RIGHT_LEFT -> {
                x0 = strokeOuterRect.right
                y0 = strokeOuterRect.centerY()
                x1 = strokeOuterRect.left
                y1 = strokeOuterRect.centerY()
            }
            Direction.BOTTOM_TOP -> {
                x0 = strokeOuterRect.centerX()
                y0 = strokeOuterRect.bottom
                x1 = strokeOuterRect.centerX()
                y1 = strokeOuterRect.top
            }
            Direction.TL_BR -> {
                x0 = strokeOuterRect.left
                y0 = strokeOuterRect.top
                x1 = strokeOuterRect.right
                y1 = strokeOuterRect.bottom
            }
            Direction.TR_BL -> {
                x0 = strokeOuterRect.right
                y0 = strokeOuterRect.top
                x1 = strokeOuterRect.left
                y1 = strokeOuterRect.bottom
            }
            Direction.BR_TL -> {
                x0 = strokeOuterRect.right
                y0 = strokeOuterRect.bottom
                x1 = strokeOuterRect.left
                y1 = strokeOuterRect.top
            }
            Direction.BL_TR -> {
                x0 = strokeOuterRect.left
                y0 = strokeOuterRect.bottom
                x1 = strokeOuterRect.right
                y1 = strokeOuterRect.top
            }
        }

        strokePaint.shader = LinearGradient(
            x0,
            y0,
            x1,
            y1,
            strokeStartColor,
            strokeEndColor,
            Shader.TileMode.MIRROR
        )

        canvas.drawPath(path, strokePaint)

        // filling the shape

        when (fillGradientDirection) {
            Direction.LEFT_RIGHT -> {
                x0 = fillRect.left
                y0 = fillRect.centerY()
                x1 = fillRect.right
                y1 = fillRect.centerY()
            }
            Direction.TOP_BOTTOM -> {
                x0 = fillRect.centerX()
                y0 = fillRect.top
                x1 = fillRect.centerX()
                y1 = fillRect.bottom
            }
            Direction.RIGHT_LEFT -> {
                x0 = fillRect.right
                y0 = fillRect.centerY()
                x1 = fillRect.left
                y1 = fillRect.centerY()
            }
            Direction.BOTTOM_TOP -> {
                x0 = fillRect.centerX()
                y0 = fillRect.bottom
                x1 = fillRect.centerX()
                y1 = fillRect.top
            }
            Direction.TL_BR -> {
                x0 = fillRect.left
                y0 = fillRect.top
                x1 = fillRect.right
                y1 = fillRect.bottom
            }
            Direction.TR_BL -> {
                x0 = fillRect.right
                y0 = fillRect.top
                x1 = fillRect.left
                y1 = fillRect.bottom
            }
            Direction.BR_TL -> {
                x0 = fillRect.right
                y0 = fillRect.bottom
                x1 = fillRect.left
                y1 = fillRect.top
            }
            Direction.BL_TR -> {
                x0 = fillRect.left
                y0 = fillRect.bottom
                x1 = fillRect.right
                y1 = fillRect.top
            }
        }

        fillPaint.shader = LinearGradient(
            x0,
            y0,
            x1,
            y1,
            fillStartColor,
            fillEndColor,
            Shader.TileMode.MIRROR
        )

        canvas.drawRoundRect(
            fillRect,
            radius,
            radius,
            fillPaint
        )
    }

    override fun setAlpha(alpha: Int) {
        strokePaint.alpha = alpha
        fillPaint.alpha = alpha

        invalidateSelf()
    }

    override fun setColorFilter(colorFilter: ColorFilter?) {
        throw RuntimeException("Color filter cannot be set to this Drawable")
    }

    override fun getOpacity(): Int {
        return PixelFormat.TRANSLUCENT
    }

    fun setStrokeColors(startColor: Int, endColor: Int) {
        this.strokeStartColor = startColor
        this.strokeEndColor = endColor

        invalidateSelf()
    }

    fun setFillColors(startColor: Int, endColor: Int) {
        this.fillStartColor = startColor
        this.fillEndColor = endColor

        invalidateSelf()
    }

    fun setRadius(radius: Float) {
        this.radius = radius

        invalidateSelf()
    }

    fun setStrokeWidth(width: Float) {
        this.strokeWidth = width

        invalidateSelf()
    }
}

该类添加了以下功能:

  • 笔触渐变的方向;
  • 填充渐变,和
  • 填充梯度方向;

答案 2 :(得分:0)

我认为我们不能为Stroke设置渐变,但我们可以使用图层列表进行相同的操作。

你可以使用你想要的渐变创建下面的可绘制xml

<item>
    <shape android:shape="rectangle">
        <!-- gradient for the stroke is set below -->
        <gradient
            android:angle="180"
            android:startColor="#555994"
            android:endColor="#b5b6d2"
            android:type="linear" />
        <corners android:radius="4dp"></corners>
    </shape>

</item>
<!-- stroke width has to be adjusted by setting left, right , top and bottom -->
<item android:left="4dp" android:right="4dp"
    android:top="4dp" android:bottom="4dp">
    <shape
        android:shape="rectangle">
        <solid android:color="@android:color/white"/>
    </shape>
</item>

您可以在布局/编程中设置上述drawable

<强> button.setBackgroundResource(R.drawable.button_background);