2017-02-01 40 views
3

custom ImageView을 만들고 onDraw 메서드를 다음과 같이 재정 의하여 ImageView의 둥근 모서리를 만듭니다. 참고안드로이드에서 Path와 RectF를 사용하여 왼쪽 상단 오른쪽 상단 왼쪽 하단 오른쪽에 둥근 모서리를 그립니다.

네 모서리를 모두 둥글게 만드는 대신 둥근 모서리를 선택적으로 만들 수 있습니까? 예를 들어 왼쪽 상단과 오른쪽 상단 모서리를 둥글게하고 하단 모서리는 그대로 둡니다. Bitmap을 통해 할 일은 solution입니다. 이 onDraw 메서드에서 및 Path 및 RectF 사용하여 찾고 있어요.

답변

13

float8 개의 값을 갖는 Path#addRoundRect() 과부하가 있으며, 4 개의 각 모서리에 대해 x 및 y 반경을 지정할 수 있습니다. 이 값은 [x, y] 쌍으로되어 있으며, 왼쪽 상단에서 시작하여 나머지는 시계 방향으로 돌아갑니다. 반올림하려는 모서리의 경우 두 쌍의 값을 반지름 값으로 설정하고 그렇지 않은 경우에는 0으로 두십시오. 예시 예를 들어

, 당신의 코드에서 사용할 수있는 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>에 있어야합니다.
<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

attrs.xml

는 차원 특성이며, 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

내가 지금 이주 이미지를 반올림하기 위해 노력 해왔다, 감사합니다, 당신의 코드는 완벽! –

+0

@ 마이크이 솔루션을 따라하고 예상대로 이미지를 배경으로 ImageView 반올림합니다. 그러나 ImageViews 배경 이미지가없고 그냥 배경색을 가지고, 작동하지 않습니다.왜 그런 일이 일어날 지 아십니까? – user2991413

+0

@ user2991413 무슨 뜻인지 모르겠습니다. 이 솔루션은'ImageView'의 배경을 가지고 아무것도하지 않습니다. –