# 圆角

圆角或圆形图片在Android是很常用的. 在CoreLibs中, 圆角相关均位于views包下的roundedimageview包中. 以下是包结构:

```
| roundedimageview
  -RoundedDrawable 圆角Drawable, RoundedImageView与RoundedTransformationBuilder
             内部均是使用RoundedDrawable来做圆角 或者圆形效果
  -RoundedImageView 圆角ImageView, 任意图片在此控件中均可显示成圆角或圆形
  -RoundedTransformationBuilder 圆角TransformationBuilder, 可配合Picasso使用产生圆角或圆形效果.
```

## RoundedDrawable

首先来看看RoundedDrawable. 实现圆角最常见的就是利用Xfermode或Shader. RoundedDrawable就是使用的BitmapShader. 具体BitmapShader的原理或者用法可以自行谷歌.

RoundedDrawable提供了两个方法将Drawable/Bitmap转换成RoundedDrawable:

```
public static Drawable fromDrawable(Drawable drawable);
public static RoundedDrawable fromBitmap(Bitmap bitmap);
```

fromDrawable方法内部最终会将Drawable中的Bitmap取出赋值给RoundedDrawable并返回. RoundedDrawable还提供了一系列方法用以描述圆角信息, 如上下左右各个角的圆角角度, 或者是否是圆形等:

```
public RoundedDrawable setCornerRadius(Corner corner, float radius);
public RoundedDrawable setCornerRadius(float topLeft, float topRight, float bottomRight, float bottomLeft);
public RoundedDrawable setOval(boolean oval);
...
```

最后在draw方法中, 则会根据这些信息进行绘制, 调用canvas.drawRoundRect或canvas.drawOval得到圆角或圆形图片. 当然RoundedDrawable内部比这里说的复杂, 其内部会对不同的scaleType做适配, 不同的Drawable做适配, 以及其他兼容性问题. 也提供了一些设置Alpha, Shader的TileMode等方法.

## RoundedImageView

我们可以使用RoundedImageView来显示圆角或圆形图片. 用法很简单:

```
XML:

<com.corelibs.views.roundedimageview.RoundedImageView
        android:layout_width="wrap_content"
        android:layout_height="wrap_content" 
        app:riv_oval="true" // 设置是否是圆形, 如果为true, 则设置的圆角效果会无效
        app:riv_corner_radius="5dp" // 四个角统一为5dp, 也可单独这是每个角
        app:riv_corner_radius_top_left="5dp" // 左上5dp
        app:riv_corner_radius_bottom_left="5dp" // 左下5dp
        app:riv_corner_radius_bottom_right="5dp" // 右下5dp
        app:riv_corner_radius_top_right="5dp" // 右上5dp
        />
```

```
代码:

RoundedImageView imageView;
imageView.setOval(true);
imageView.setCornerRadius(50);
imageView.setCornerRadius(50, 50, 50, 50);
```

用法很简单. 下面看看内部大概的原理. 其内部覆写了一系列的setImageXXX方法, 这些方法中均利用RoundedDrawable的fromBitmap或fromDrawable方法将其转换为RoundedDrawable, 并将RoundedDrawable设置到ImageView中. 通过RoundedImageView的外部方法收集圆角信息, 并将这些信息通过updateAttrs方法传递给RoundedDrawable.

```
  @Override
  public void setImageDrawable(Drawable drawable) {
    mResource = 0;
    mDrawable = RoundedDrawable.fromDrawable(drawable);
    updateDrawableAttrs();
    super.setImageDrawable(mDrawable);
  }
```

```
  private void updateAttrs(Drawable drawable) {
    if (drawable == null) { return; }

    if (drawable instanceof RoundedDrawable) {
      ((RoundedDrawable) drawable)
          .setScaleType(mScaleType)
          .setBorderWidth(mBorderWidth)
          .setBorderColor(mBorderColor)
          .setOval(mIsOval)
          .setTileModeX(mTileModeX)
          .setTileModeY(mTileModeY);

      if (mCornerRadii != null) {
        ((RoundedDrawable) drawable)
            .setCornerRadius(
                mCornerRadii[0], mCornerRadii[1], mCornerRadii[2], mCornerRadii[3]);
      }

      applyColorMod();
    } else if (drawable instanceof LayerDrawable) {
      // loop through layers to and set drawable attrs
      LayerDrawable ld = ((LayerDrawable) drawable);
      for (int i = 0, layers = ld.getNumberOfLayers(); i < layers; i++) {
        updateAttrs(ld.getDrawable(i));
      }
    }
  }
```

每次ImageView进行绘制的时候, 均会调用RoundedDrawable的draw方法, 这样就实现了圆角/圆形图片的功能.

## RoundedTransformationBuilder

如果觉得使用自定义控件太麻烦, 则可以使用RoundedTransformationBuilder配合Picasso实现圆角. 使用系统默认ImageView即可. 首先看看用法:

```
圆形:

int size = (int) getResources().getDimension(R.dimen.avatar_height);
Picasso.with(context).load(user.icon).resize(size, size).centerCrop()
                    .transform(new RoundedTransformationBuilder().oval(true)
                            .build()).into(ivIcon);

圆角:

Picasso.with(context).load(user.icon).resize(size, size).centerCrop()
                    .transform(new RoundedTransformationBuilder().cornerRadius(50)
                            .build()).into(ivIcon);

Picasso.with(context).load(user.icon).resize(size, size).centerCrop()
                    .transform(new RoundedTransformationBuilder()
                            .cornerRadiusTopLeft(50)
                            .cornerRadiusBottomLeft(50)
                            .cornerRadiusTopRight(50)
                            .cornerRadiusBottomRight(50)
                            .build()).into(ivIcon);
```

RoundedTransformationBuilder内部也是使用了RoundedDrawable.fromBitmap(source)方法, 将源Bitmap转化为目标Bitmap. 具体原理是十分简单, 这里就不做过多解释.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://ryan-8.gitbook.io/android-architecture-journey/widgets/rounded.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
