Canvas API (Part 2) 자르기 방법 모음에 대한 자세한 설명
이 섹션 소개:
이 섹션에서는 계속해서 Android 드로잉 시리즈 - Canvas API(2부)에 대해 자세히 설명합니다. ClipXxx 메서드 제품군이 포함되었습니다! 문서에는 clipPath( ), clipRect( ), clipRegion( ) 세 가지 유형의 Clip 메소드가 제공되는 것을 볼 수 있습니다.
Path, Rect 및 Region의 다양한 조합을 통해 거의 모든 모양의 자르기 영역!
Path: 열린 곡선이나 닫힌 곡선 또는 복잡한 선 집합일 수 있습니다.
Rect: 직사각형 영역
Region: 예를 들어 두 영역의 조합으로 이해될 수 있습니다. 영역은 뺄셈, 합집합, 의심 등을 함께 추가할 수 있습니다!
Region.Op는 Region에서 지원하는 지역 간 작업 유형을 정의합니다! 그것에 대해서는 나중에 이야기하겠습니다. 또 한 가지 말씀드릴 점은 우리가 일반적으로 클리핑이라고 이해하는 것은 기존 그래픽을 클리핑하는 것일 수도 있지만 Android에서는 클리핑이 캔버스에 클립은 그리기 전에 수행해야 합니다. 그림을 그린 후 캔버스에 클립하면 영향을 미치지 않습니다. 그려진 그래픽으로 이동하세요. 클립은 그래픽이 아닌 캔버스용이라는 점을 기억하세요! 글쎄요, BB는 없습니다. 이 섹션을 직접 시작하겠습니다!
공식 API 문서: Canvas
1.Region.Op 조합 방법 상세 설명
사실 난이도는 이 정도입니다. Region은 영역을 나타내며, 이는 특정 폐쇄 영역을 나타냅니다. 캔버스 레이어! 물론 시간이 있으면 이 클래스를 혼자서 천천히 추론할 수 있으며 우리가 일반적으로 집중하는 것은 열거형 값 중 하나일 뿐입니다. Op
각 열거형 값의 역할을 살펴보겠습니다. 두 개의 자르기 영역 A와 B를 가정하고 Region.Op에 해당하는 열거 값을 호출합니다.
DIFFERENCE: A와 B의 차이 세트 범위, 즉 A - B, 이 범위 내에서만 그리기
INTERSECT: 즉, A와 B의 intersection 범위가 표시됩니다. 이 범위 내의 그림 콘텐츠만 표시됩니다.
UNION: 즉, union 범위입니다. 즉, 둘 다에 포함된 범위의 그리기 내용이 표시됩니다.
XOR: A와 B의 complement 범위, 이 예에서는 B를 제외한 A의 범위만 표시됩니다. 이 범위 내의 그림 내용이 표시됩니다.
REVERSE_DIFFERENCE: B와 A의 차이 세트 범위, 즉 B - A, 이 범위 내의 그림 내용만 표시됩니다. A와 B의 차이에 관계없이 세트 상태에서는 B의 전체 범위가 표시됩니다. A와 교차하면 A의 교차 범위가 포함됩니다.
세트를 학습한 경우에는 명확해집니다. 벤(벤다이어그램)을 그려보세요. Pass를 아직 배우지 않았다면? 괜찮아, 예시를 써서 해보자 해당 결과~! 브러시를 초기화하고 직사각형을 그리는 메서드를 작성하세요.
private void init() { mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setStrokeWidth(6); mPaint.setColor(getResources().getColor(R.color.blush)); } private void drawScene(Canvas canvas){ canvas.drawRect(0, 0, 200, 200, mPaint); }
Op.DIFFERENCE:
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.DIFFERENCE); //第二个 drawScene(canvas);
Result:
(10,10)과 (50,50)을 시작점으로 100*100의 직사각형 두 개를 잘라서 다음을 얻습니다. 자르기 결과는 다음과 같습니다.
A와 B의 차이 집합 = A - (A와 B의 교차점)
Op.INTERSECT:
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.INTERSECT); //第二个 drawScene(canvas);
Result:
( 10) ,10) 및 (50,50)을 시작점으로 사용하고 100*100 직사각형 두 개를 잘라냅니다. A와 B의 교차점 = A와 B의 교차점
Op. UNION:
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(40, 40, 140, 140, Region.Op.UNION); //第二个 drawScene(canvas);
Result:
(10,10)과 (50,50)에서 두 개의 100*100 직사각형을 시작점으로 자르고 자르기 결과는 다음과 같습니다.A B의 합집합 = A의 면적 + B의 면적
Op. , 100*100의 직사각형 2개를 잘라낸 결과는 다음과 같습니다. A와 B의 보수 = A와 B의 집합 - A와 B의 교차점
Op.REVERSE_DIFFERENCE
:
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.XOR); //第二个 drawScene(canvas);
Result:
두 개의 100*100 직사각형을 (10,10)과 (50,50)을 시작점으로 잘라냅니다. 자르기 결과는 다음과 같습니다. B와 A의 차이 집합 = B - A와 B의 교차점
Op.REPLACE
canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.REVERSE_DIFFERENCE); //第二个 drawScene(canvas);
Result:
started at (10,10) 및 (50,50)을 입력하고 100*100 직사각형 두 개를 잘라낸 결과는 다음과 같습니다. A와 B의 수집 상태에 관계없이 B의 범위는 A와 교차하는 경우 전체의 교차 범위로 표시됩니다. A는 다루겠습니다.
2.Region.Op 사용 예:
예 참조: Android 2D 그래픽 학습(2), 캔버스 파트 2, 캔버스 자르기 및 영역, RegionIterator
실행 효과 그림
:canvas.clipRect(10, 10, 110, 110); //第一个 canvas.clipRect(50, 50, 150, 150, Region.Op.REPLACE); //第二个 drawScene(canvas);구현 분석:
초기화 중에 너비와 높이를 구한 다음 루프를 반복하면 그림이 선으로 나누어진다는 것을 알 수 있습니다. i * 각 선의 높이. 높이보다 크지 않은 경우 선이 두 가지 상황으로 구분되는 경우가 바로 UNINO의 절단 방법입니다. 마지막으로 이때 이미지가 표시되는지 판단하고 숨기기 상황과 표시 상황을 다르게 처리한 후 마지막으로 무효화()를 호출합니다. 다시 그려라! 아주 간단합니다. 스스로 이해하세요~
또 다른 요점: 캔버스 변환은clipRegion
3.clipRect 메서드에 대한 자세한 설명:
clipRect는 7개의 오버로드된 메서드를 제공합니다.
Rect: 자르기 영역의 범위를 정의하는 데 사용되는 Rect 객체입니다. Rect와 RectF는 비슷한 기능을 가지고 있지만 제공된 방법과 정확도가 다릅니다
left: 왼쪽 position of the 직사각형 자르기 영역:top
: 직사각형 자르기 영역의 상단 위치right
: 직사각형 자르기 영역의 오른쪽 위치bottom
: 직사각형 자르기 영역의 하단 위치op
: 자르기 영역의 조합위 네 가지 A 값은 부동 소수점 유형 또는 정수 유형일 수 있습니다.
사용 예:
/** * Created by Jay on 2015/11/10 0010. */ public class MyView extends View{ private Bitmap mBitmap = null; private int limitLength = 0; // private int width; private int heigth; private static final int CLIP_HEIGHT = 50; private boolean status = HIDE;//显示还是隐藏的状态,最开始为HIDE private static final boolean SHOW = true;//显示图片 private static final boolean HIDE = false;//隐藏图片 public MyView(Context context) { this(context, null); } public MyView(Context context, AttributeSet attrs) { super(context, attrs); mBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.img_meizi); limitLength = width = mBitmap.getWidth(); heigth = mBitmap.getHeight(); } public MyView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { Region region = new Region(); int i = 0; while (i * CLIP_HEIGHT <= heigth) {//计算clip的区域 if (i % 2 == 0) { region.union(new Rect(0, i * CLIP_HEIGHT, limitLength, (i + 1) * CLIP_HEIGHT)); } else { region.union(new Rect(width - limitLength, i * CLIP_HEIGHT, width, (i + 1) * CLIP_HEIGHT)); } i++; } canvas.clipRegion(region); canvas.drawBitmap(mBitmap, 0, 0, new Paint()); if (status == HIDE) {//如果此时是隐藏 limitLength -= 10; if(limitLength = width) status=HIDE; } invalidate(); } }실행 결과
위에서 예를 들어, 찾았어? ClipRect는 캔버스 변환의 영향을 받습니다. 흰색 영역은 꽃이 피지 않은 영역이므로 ClipRect는 캔버스를 자릅니다. 그리고 우리의 그림은 잘려진 캔버스에 완성되었습니다! 이 영역을 벗어나는 내용은 표시되지 않습니다!
4.clipPath 메소드에 대한 자세한 설명: clipRect에 비해, 사용 방법은 매우 간단합니다. 그냥 전달하세요!사용 예
:
여기에서는 이전에 ImageView에서 작성한 원형 ImageView 예를 재사용합니다~구현 코드:
Customized ImageView: RoundImageView.javamPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setColor(Color.BLACK); mPaint.setTextSize(60); canvas.translate(300,300); canvas.clipRect(100, 100, 300, 300); //设置显示范围 canvas.drawColor(Color.WHITE); //白色背景 canvas.drawText("双11,继续吃我的狗粮...", 150, 300, mPaint); //绘制字符串레이아웃 코드:
activity_main.xml:
/** * Created by coder-pig on 2015/7/18 0018. */ public class RoundImageView extends ImageView { private Bitmap mBitmap; private Rect mRect = new Rect(); private PaintFlagsDrawFilter pdf = new PaintFlagsDrawFilter(0, Paint.ANTI_ALIAS_FLAG); private Paint mPaint = new Paint(); private Path mPath=new Path(); public RoundImageView(Context context, AttributeSet attrs) { super(context, attrs); init(); } //传入一个Bitmap对象 public void setBitmap(Bitmap bitmap) { this.mBitmap = bitmap; } private void init() { mPaint.setStyle(Paint.Style.STROKE); mPaint.setFlags(Paint.ANTI_ALIAS_FLAG); mPaint.setAntiAlias(true);// 抗锯尺 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if(mBitmap == null) { return; } mRect.set(0,0,getWidth(),getHeight()); canvas.save(); canvas.setDrawFilter(pdf); mPath.addCircle(getWidth() / 2, getWidth() / 2, getHeight() / 2, Path.Direction.CCW); canvas.clipPath(mPath, Region.Op.REPLACE); canvas.drawBitmap(mBitmap, null, mRect, mPaint); canvas.restore(); } }
MainActivity.java
:<com.jay.demo.imageviewdemo.RoundImageView android:id="@+id/img_round" android:layout_width="200dp" android:layout_height="200dp" android:layout_margin="5px"/>렌더링 실행:
또한 이 방법을 사용하여 만든 둥근 ImageView는 페인트 및 캔버스용으로 설정하더라도 가장자리가 들쭉날쭉합니다. 앤티앨리어싱은 쓸모가 없습니다~ 요구 사항이 높으면 Xfermode-PorterDuff를 사용하여 이미지 셔플링을 설정하여 이를 달성할 수 있습니다. 기본적으로 앨리어싱이 없습니다. 다음을 볼 수 있습니다. Android의 기본 입문 튜토리얼 - 8.3.6 Paint API - Xfermode 및 PorterDuff에 대한 자세한 설명(3)
5. 이 섹션의 샘플 코드를 다운로드하세요:
이 섹션의 요약:
좋아, 이 섹션에서는 Canvas를 자르는 방법을 설명합니다. 세 가지 메서드:clipPath(),clipRect(), ClipRegion()의 경우 난이도는 마지막에 있어야 합니다. 실제로는 6가지 Op 조합이 어렵지 않습니다. 그냥 개념이니 그냥 앞부분에 넣어서 소화하면 되는데,clipPath(),clipRect()는 어렵지 않아요~ 네 오늘 더블11인데 잘 하셨나요~