GradientDrawable

GradientDrawable 可以绘制渐变的颜色,但现在的 APP 好像已经不流行渐变色的按钮了。

GradientDrawable 的功能非常强大,有了它,几乎不需要使用 ShapeDrawable 了。


有时候你只需要半个圆角。

public void setCornerRadii(float[] radii)

设置圆角。

public void setCornerRadius(float radius) 

可以绘制 ShapeDrawable 无法做到的边框。

public void setStroke(int width, ColorStateList colorStateList, float dashWidth, float dashGap) 

设置形状

* @param shape The desired shape for this drawable: {@link #LINE},
     *              {@link #OVAL}, {@link #RECTANGLE} or {@link #RING}
public void setShape(int shape) 


Fill 和 Stroke 一样,也可以设置为 ColorStateList,这意味仅仅依靠 GradientDrawable 就能做出很棒的点击效果了(api 21)。

当 View 的 state 改变时,会触发 Drawable 的 onStateChange 函数。

   @Override
    protected boolean onStateChange(int[] stateSet) {
        boolean invalidateSelf = false;

        final GradientState s = mGradientState;
        final ColorStateList solidColors = s.mSolidColors;
        if (solidColors != null) {
            final int newColor = solidColors.getColorForState(stateSet, 0);
            final int oldColor = mFillPaint.getColor();
            if (oldColor != newColor) {
                mFillPaint.setColor(newColor);
                invalidateSelf = true;
            }
        }

        final Paint strokePaint = mStrokePaint;
        if (strokePaint != null) {
            final ColorStateList strokeColors = s.mStrokeColors;
            if (strokeColors != null) {
                final int newColor = strokeColors.getColorForState(stateSet, 0);
                final int oldColor = strokePaint.getColor();
                if (oldColor != newColor) {
                    strokePaint.setColor(newColor);
                    invalidateSelf = true;
                }
            }
        }

        if (s.mTint != null && s.mTintMode != null) {
            mTintFilter = updateTintFilter(mTintFilter, s.mTint, s.mTintMode);
            invalidateSelf = true;
        }

        if (invalidateSelf) {
            invalidateSelf();
            return true;
        }

        return false;
    }

Fill 和 Stroke 的 Paint 都会从对应的 ColorStateList 中选取适合的色彩,然后重画。


最后看看 draw 函数的关键部分(其中 useLayer 那块看不懂。。。)

  switch (st.mShape) {
            case RECTANGLE:
                if (st.mRadiusArray != null) {
                    buildPathIfDirty();
                    canvas.drawPath(mPath, mFillPaint);
                    if (haveStroke) {
                        canvas.drawPath(mPath, mStrokePaint);
                    }
                } else if (st.mRadius > 0.0f) {
                    // since the caller is only giving us 1 value, we will force
                    // it to be square if the rect is too small in one dimension
                    // to show it. If we did nothing, Skia would clamp the rad
                    // independently along each axis, giving us a thin ellipse
                    // if the rect were very wide but not very tall
                    float rad = Math.min(st.mRadius,
                            Math.min(mRect.width(), mRect.height()) * 0.5f);
                    canvas.drawRoundRect(mRect, rad, rad, mFillPaint);
                    if (haveStroke) {
                        canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
                    }
                } else {
                    if (mFillPaint.getColor() != 0 || colorFilter != null ||
                            mFillPaint.getShader() != null) {
                        canvas.drawRect(mRect, mFillPaint);
                    }
                    if (haveStroke) {
                        canvas.drawRect(mRect, mStrokePaint);
                    }
                }
                break;
            case OVAL:
                canvas.drawOval(mRect, mFillPaint);
                if (haveStroke) {
                    canvas.drawOval(mRect, mStrokePaint);
                }
                break;
            case LINE: {
                RectF r = mRect;
                float y = r.centerY();
                if (haveStroke) {
                    canvas.drawLine(r.left, y, r.right, y, mStrokePaint);
                }
                break;
            }
            case RING:
                Path path = buildRing(st);
                canvas.drawPath(path, mFillPaint);
                if (haveStroke) {
                    canvas.drawPath(path, mStrokePaint);
                }
                break;
        }


使用和 InsetDrawable 中一样的方法,获得实际绘制大小 Rect:

    private boolean ensureValidRect() {
        if (mGradientIsDirty) {
            mGradientIsDirty = false;

            Rect bounds = getBounds();
            float inset = 0;

            if (mStrokePaint != null) {
                inset = mStrokePaint.getStrokeWidth() * 0.5f;
            }

            final GradientState st = mGradientState;

            mRect.set(bounds.left + inset, bounds.top + inset,
                      bounds.right - inset, bounds.bottom - inset);






你可能感兴趣的:(GradientDrawable)