首页 > 安全资讯 >

shape标签研究

16-09-27

shape标签研究

用处

标签一般可用于一个View的background属性,或者嵌入到 等标签的某个 里使用。它有以下属性标签可使用。

0.几个内属性

android:useLevel
对应GradientDrawable源码:

private Path buildRing(GradientState st) {
    if (mRingPath != null && (!st.mUseLevelForShape || !mPathIsDirty)) return mRingPath;
    mPathIsDirty = false;

    float sweep = st.mUseLevelForShape ? (360.0f * getLevel() / 10000.0f) : 360f;
    ···
    ···
    ···
}

这里的useLevel对应mUseLevelForShape,区别下面提到的渐变里useLevel对应mUseLevel;
只有在建立环的时候会用到这个属性,默认true可指定任一阶段的环,也可作为进度条一部分,为false的话为整个环。也就是说shape=”ring”时才有用。

android:dither

/**
 * Set to true to have the drawable dither its colors when drawn to a device
 * with fewer than 8-bits per color component. This can improve the look on
 * those devices, but can also slow down the drawing a little.
 */
public void setDither(boolean dither) {}

抖色,提升效果,会降低绘画速度

android:innerRadius // 内环半径
android:innerRadiusRatio // 缺省内环半径比率
以下是取值的地方,可知shape=”ring”时才有效,且mInnerRadius不存在时mInnerRadiusRatio才有效,mInnerRadiusRatio默认值是3.0f。

if (shapeType == RING) {
    st.mInnerRadius = a.getDimensionPixelSize(
            com.android.internal.R.styleable.GradientDrawable_innerRadius, -1);
    if (st.mInnerRadius == -1) {
        st.mInnerRadiusRatio = a.getFloat(
                com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
    }

以下是使用值的地方,可知没有指定内环半径mInnerRadius时使用缺省内环半径,值为bounds.width()/st.mInnerRadiusRatio,而mInnerRadius默认值是3.0f,也就是说什么值都不填的话默认环的内环半径是View的三分之一长。

private Path buildRing(GradientState st) {
   ···
   ···
   ···
   // inner radius
   float radius = st.mInnerRadius != -1 ?
           st.mInnerRadius : bounds.width() / st.mInnerRadiusRatio;
   ···
   ···
   ···

android:shape
形状,默认矩形,有四种选择
ring=环
line=线
oval=椭圆
rectangle=矩形

int shapeType = a.getInt(
    com.android.internal.R.styleable.GradientDrawable_shape, RECTANGLE);

android:thickness
android:thicknessRatio

if (shapeType == RING) {
    st.mInnerRadius = a.getDimensionPixelSize(
            com.android.internal.R.styleable.GradientDrawable_innerRadius, -1);
    if (st.mInnerRadius == -1) {
        st.mInnerRadiusRatio = a.getFloat(
                com.android.internal.R.styleable.GradientDrawable_innerRadiusRatio, 3.0f);
    }
    st.mThickness = a.getDimensionPixelSize(
            com.android.internal.R.styleable.GradientDrawable_thickness, -1);
    if (st.mThickness == -1) {
        st.mThicknessRatio = a.getFloat(
                com.android.internal.R.styleable.GradientDrawable_thicknessRatio, 9.0f);
    }
    st.mUseLevelForShape = a.getBoolean(
            com.android.internal.R.styleable.GradientDrawable_useLevel, true);
}

可知,也是在环下有效。其实是决定环厚度的,玩法和innerRadius一样,thicknessRatio默认值为9。


1.

功能:控制圆角半径

    // 设置右下角的圆角半径为2dp

根据源码GradientDrawable

else if (name.equals("corners")) {
      a = r.obtainAttributes(attrs,
              com.android.internal.R.styleable.DrawableCorners);
      int radius = a.getDimensionPixelSize(
              com.android.internal.R.styleable.DrawableCorners_radius, 0);
      setCornerRadius(radius);
      int topLeftRadius = a.getDimensionPixelSize(
              com.android.internal.R.styleable.DrawableCorners_topLeftRadius, radius);
      int topRightRadius = a.getDimensionPixelSize(
              com.android.internal.R.styleable.DrawableCorners_topRightRadius, radius);
      int bottomLeftRadius = a.getDimensionPixelSize(
              com.android.internal.R.styleable.DrawableCorners_bottomLeftRadius, radius);
      int bottomRightRadius = a.getDimensionPixelSize(
              com.android.internal.R.styleable.DrawableCorners_bottomRightRadius, radius);
      if (topLeftRadius != radius || topRightRadius != radius ||
              bottomLeftRadius != radius || bottomRightRadius != radius) {
          // The corner radii are specified in clockwise order (see Path.addRoundRect())
          setCornerRadii(new float[] {
                  topLeftRadius, topLeftRadius,
                  topRightRadius, topRightRadius,
                  bottomRightRadius, bottomRightRadius,
                  bottomLeftRadius, bottomLeftRadius
          });
      }
      a.recycle();
  }
...
...
...
public void setCornerRadii(float[] radii) {
    mRadiusArray = radii;    // ;四个属性设置到mRadiusArray
    if (radii == null) {
        mRadius = 0;
    }
}
···
···
···
case RECTANGLE:
    if (st.mRadiusArray != null) {   // ;优先使用mRadiusArray
        if (mPathIsDirty || mRectIsDirty) {
            mPath.reset();
            mPath.addRoundRect(mRect, st.mRadiusArray, Path.Direction.CW);
            mPathIsDirty = mRectIsDirty = false;
        }
        canvas.drawPath(mPath, mFillPaint);
        if (haveStroke) {
            canvas.drawPath(mPath, mStrokePaint);
        }
    } else if (st.mRadius > 0.0f) {    // ;mRadiusArray为空才使用mRadius
        // 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 = st.mRadius;
        float r = Math.min(mRect.width(), mRect.height()) * 0.5f;
        if (rad > r) {
            rad = r;
        }
        canvas.drawRoundRect(mRect, rad, rad, mFillPaint);
        if (haveStroke) {
            canvas.drawRoundRect(mRect, rad, rad, mStrokePaint);
        }
    } else {
        if (mFillPaint.getColor() != 0 || mColorFilter != null ||
                mFillPaint.getShader() != null) {
            canvas.drawRect(mRect, mFillPaint);
        }
        if (haveStroke) {
            canvas.drawRect(mRect, mStrokePaint);
        }
    }
    break;

可以发现,设置了topLeftRadius等四个属性时,以topLeftRadius等四个属性的值为准。


2.

功能:控制渐变

                     // 渐变半径

android:useLevel=”true”,渐变进度,View.getBackground().setLevel(int)设置渐变的进度,取值[0,10000]。

查看关于”angle”的源码:

if (gradientType == LINEAR_GRADIENT) {
    int angle = (int)a.getFloat(
            com.android.internal.R.styleable.GradientDrawableGradient_angle, 0);
    angle %= 360;
    if (angle % 45 != 0) {
        throw new XmlPullParserException(a.getPositionDescription()
                + " tag requires 'angle' attribute to "
                + "be a multiple of 45");
    }

    switch (angle) {
    case 0:
        st.mOrientation = Orientation.LEFT_RIGHT;
        break;
    case 45:
        st.mOrientation = Orientation.BL_TR;
        break;
    case 90:
        st.mOrientation = Orientation.BOTTOM_TOP;
        break;
    case 135:
        st.mOrientation = Orientation.BR_TL;
        break;
    case 180:
        st.mOrientation = Orientation.RIGHT_LEFT;
        break;
    case 225:
        st.mOrientation = Orientation.TR_BL;
        break;
    case 270:
        st.mOrientation = Orientation.TOP_BOTTOM;
        break;
    case 315:
        st.mOrientation = Orientation.TL_BR;
        break;
    }
}

可以发现:android:angle=”45”,渐变角度,只对线性渐变有效,必须是45的倍数,渐变逆时针旋转的度数。

android:type=”radial”,渐变类型,”radial”,辐射状,搭配”gradientRadius”服用效果才有效果;”linear”,线性;”sweep”,扇形。

android:centerColor渐变中间颜色,搭配”centerX”和”centerY”作为中间颜色的坐标,取值[0,1]。

设置了 填充色的话会渐变会失效。


3.

功能:控制内间隔

else if (name.equals("padding")) {
    a = r.obtainAttributes(attrs,
            com.android.internal.R.styleable.GradientDrawablePadding);
    mPadding = new Rect(
            a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.GradientDrawablePadding_left, 0),
            a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.GradientDrawablePadding_top, 0),
            a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.GradientDrawablePadding_right, 0),
            a.getDimensionPixelOffset(
                    com.android.internal.R.styleable.GradientDrawablePadding_bottom, 0));
    a.recycle();
    mGradientState.mPadding = mPadding;
}

很纯粹的控制控件的padding。


4.

功能:控制宽高

如果是作为一个View的Background设置了这个shape的size的话,会取View和Background的宽度最大值作为View的最小宽度,可参见以下View的源码得知。

/**
 * Returns the suggested minimum width that the view should use. This
 * returns the maximum of the view's minimum width)
 * and the background's minimum width
 *  ({@link android.graphics.drawable.Drawable#getMinimumWidth()}).
 * 

* When being used in {@link #onMeasure(int, int)}, the caller should still * ensure the returned width is within the requirements of the parent. * * @return The suggested minimum width of the view. */ protected int getSuggestedMinimumWidth() { return (mBackground == null) ? mMinWidth : max(mMinWidth, mBackground.getMinimumWidth()); }


5.

功能:控制填充色

else if (name.equals("solid")) {
    a = r.obtainAttributes(attrs,
            com.android.internal.R.styleable.GradientDrawableSolid);
    int argb = a.getColor(
            com.android.internal.R.styleable.GradientDrawableSolid_color, 0);
    a.recycle();
    setColor(argb);
}

6.

功能:控制描边

               // 将描边分段的话段与段之间间隔长度
 else if (name.equals("stroke")) {
    a = r.obtainAttributes(attrs,
            com.android.internal.R.styleable.GradientDrawableStroke);
    int width = a.getDimensionPixelSize(
            com.android.internal.R.styleable.GradientDrawableStroke_width, 0);
    int color = a.getColor(
            com.android.internal.R.styleable.GradientDrawableStroke_color, 0);
    float dashWidth = a.getDimension(
            com.android.internal.R.styleable.GradientDrawableStroke_dashWidth, 0);
    if (dashWidth != 0.0f) {
        float dashGap = a.getDimension(
                com.android.internal.R.styleable.GradientDrawableStroke_dashGap, 0);
        setStroke(width, color, dashWidth, dashGap);
    } else {
        setStroke(width, color);
    }
    a.recycle();
}
相关文章
最新文章
热点推荐