2017-02-01 7 views
3

custom ImageViewを作成し、onDrawメソッドを次のようにオーバーライドすると、角が丸くなります。参照AndroidのPathおよびRectFを使用して、左上の上端の右上の左下に右隅を描画

どのように四隅を丸くするのではなく、選択的に丸い角を作ることができますか?たとえば、左上と右上隅を丸め、下隅をそのままにします。ここにはBitmapを通して行うべきsolutionがあります。私はこのonDrawメソッドでそれをやって、PathとRectFだけを使って探しています。

答えて

13

floatの8つの値をとる過負荷があり、4つのコーナーのそれぞれについてxとyの半径を指定できます。これらの値は[x、y]のペアで、左上隅から始まり残りの部分を時計回りにしています。丸めたいコーナーについては、ペアの両方の値を半径値に設定し、ペアの値をゼロにします。例示的な例として

、スニペットに使用することができるPathが返される簡単な方法:あなたの例の説明当たり

private Path getPath(float radius, boolean topLeft, boolean topRight, 
        boolean bottomRight, boolean bottomLeft) { 

    final Path path = new Path(); 
    final float[] radii = new float[8]; 

    if (topLeft) { 
     radii[0] = radius; 
     radii[1] = radius; 
    } 

    if (topRight) { 
     radii[2] = radius; 
     radii[3] = radius; 
    } 

    if (bottomRight) { 
     radii[4] = radius; 
     radii[5] = radius; 
    } 

    if (bottomLeft) { 
     radii[6] = radius; 
     radii[7] = radius; 
    } 

    path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 
         radii, Path.Direction.CW); 

    return path; 
} 

、左上と右上の角を丸める:

@Override 
protected void onDraw(Canvas canvas) { 
    float radius = getContext().getResources().getDimension(R.dimen.round_corner_radius); 
    Path path = getPath(radius, true, true, false, false); 
    canvas.clipPath(path); 
    super.onDraw(canvas); 
} 

常に、私はonDraw()メソッドを可能な限り緊密に保ち、他の場所に絶対にある必要のないものを移動することをお勧めします。たとえば、半径のリソース値はコンストラクタで取得し、フィールドに保持することができます。さらに、Pathは、必要な場合にのみ構築することができます。すなわち、Viewのサイズが変化したとき、または半径または選択されたコーナーが変化したとき。

これをテストするために簡単なカスタムImageViewをまとめたので、ここでは上記の点を示します。このカスタムViewには、コーナーの半径と丸みのあるコーナーをレイアウトに設定できるXML属性も用意されています。 XMLについては

public class RoundishImageView extends ImageView { 

    public static final int CORNER_NONE = 0; 
    public static final int CORNER_TOP_LEFT = 1; 
    public static final int CORNER_TOP_RIGHT = 2; 
    public static final int CORNER_BOTTOM_RIGHT = 4; 
    public static final int CORNER_BOTTOM_LEFT = 8; 
    public static final int CORNER_ALL = 15; 

    private static final int[] CORNERS = {CORNER_TOP_LEFT, 
              CORNER_TOP_RIGHT, 
              CORNER_BOTTOM_RIGHT, 
              CORNER_BOTTOM_LEFT}; 

    private final Path path = new Path(); 
    private int cornerRadius; 
    private int roundedCorners; 

    public RoundishImageView(Context context) { 
     this(context, null); 
    } 

    public RoundishImageView(Context context, AttributeSet attrs) { 
     this(context, attrs, 0); 
    } 

    public RoundishImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 

     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.RoundishImageView); 
     cornerRadius = a.getDimensionPixelSize(R.styleable.RoundishImageView_cornerRadius, 0); 
     roundedCorners = a.getInt(R.styleable.RoundishImageView_roundedCorners, CORNER_NONE); 
     a.recycle(); 
    } 

    public void setCornerRadius(int radius) { 
     if (cornerRadius != radius) { 
      cornerRadius = radius; 
      setPath(); 
      invalidate(); 
     } 
    } 

    public int getCornerRadius() { 
     return cornerRadius; 
    } 

    public void setRoundedCorners(int corners) { 
     if (roundedCorners != corners) { 
      roundedCorners = corners; 
      setPath(); 
      invalidate(); 
     } 
    } 

    public boolean isCornerRounded(int corner) { 
     return (roundedCorners & corner) == corner; 
    } 

    @Override 
    protected void onDraw(Canvas canvas) { 
     if (!path.isEmpty()) { 
      canvas.clipPath(path); 
     } 

     super.onDraw(canvas); 
    } 

    @Override 
    protected void onSizeChanged(int w, int h, int oldw, int oldh) { 
     super.onSizeChanged(w, h, oldw, oldh); 
     setPath(); 
    } 

    private void setPath() { 
     path.rewind(); 

     if (cornerRadius >= 1f && roundedCorners != CORNER_NONE) { 
      final float[] radii = new float[8]; 

      for (int i = 0; i < 4; i++) { 
       if (isCornerRounded(CORNERS[i])) { 
        radii[2 * i] = cornerRadius; 
        radii[2 * i + 1] = cornerRadius; 
       } 
      } 

      path.addRoundRect(new RectF(0, 0, getWidth(), getHeight()), 
           radii, Path.Direction.CW); 
     } 
    } 
} 

動作するように属性を、以下では、プロジェクトのres/values/フォルダにこのファイルを置くか、すでにそこにあるかもしれないものに追加することによって行うことができます、あなたの<resources>にする必要があります。

attrs.xml

<resources> 
    <declare-styleable name="RoundishImageView"> 
     <attr name="cornerRadius" format="dimension" /> 
     <attr name="roundedCorners"> 
      <flag name="topLeft" value="1" /> 
      <flag name="topRight" value="2" /> 
      <flag name="bottomRight" value="4" /> 
      <flag name="bottomLeft" value="8" /> 
      <flag name="all" value="15" /> 
     </attr> 
    </declare-styleable> 
</resources> 

cornerRadiusは、ディメンション属性であり、dp又はpx値として指定されるべきです。 roundedCornersはフラグ属性で、パイプ文字「|」を使用して複数のコーナーを選択できます。たとえば:

<com.mycompany.myapp.RoundishImageView 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:id="@+id/riv" 
    android:layout_width="wrap_content" 
    android:layout_height="wrap_content" 
    android:adjustViewBounds="true" 
    android:scaleType="fitXY" 
    android:src="@drawable/magritte" 
    app:cornerRadius="@dimen/round_corner_radius" 
    app:roundedCorners="topLeft|topRight" /> 

screenshot

+1

ありがとうございました、私はあなたのコードは完璧で、今2週間の画像を丸めるしようとしています! –

+0

@Mike私はこの解決策に従って、画像を背景として持つ画像ビューを、予想どおりに丸めています。しかし、背景画像を持っておらず、ちょうど背景色を持っているImageViewsでは、それは機能しません。なぜそれが起こるか知っていますか? – user2991413

+0

@ user2991413あなたが何を意味するのか分かりません。この解決策は、 'ImageView'のバックグラウンドでは何もしません。 –

関連する問題