Paint API - Xfermode 및 PorterDuff에 대한 자세한 설명(2)
이 섹션 소개:
이전 섹션에서 우리는 Xfermode의 사망한(구식) 두 아들에 대해 배웠습니다: AvoidXfermode, PixelXorXfermode, 다소 유용하긴 하지만 결국 제거되었습니다. 이 섹션에서는 아직 살아있는 Xfermode의 셋째 아들에 대해 알아봅니다. PorterDuffXfermode
먼저 공식 API 문서인 PorterDuffXfermode에 주목해 보겠습니다. ! 문서에는 내용이 거의 포함되어 있지 않습니다.
매개변수는 하나뿐입니다: PorterDuff.Mode 모드이며 Android는 16가지 이미지 혼합 모드를 제공합니다. 두 개의 레이어를 결합하여 서로 다른 결과를 얻을 수 있고 서로 다른 모드에 따라 표시할 수 있다는 것을 이해합니다! 16가지 믹싱 모드의 결과는 다음과 같습니다.
여기에는 두 개의 레이어가 있습니다. 첫 번째 사진은 대상 사진(DST)이고 두 번째 사진은 원본 사진(SRC)입니다!
물론 문서에서 사용 가능한 모드는 16개가 아니라 18개이며 두 가지 새로운 모드인 ADD 및 OVERLAY
음, 더 이상 말할 필요도 없습니다. 실제로는 코드가 가장 좋습니다. , 이 섹션에서는 이러한 18가지 모드를 확인하는 코드를 작성합니다!
PS: PorterDuff라는 이름은 실제로 두 이름의 조합입니다: Tomas Proter와 Tom Duff. SIGGRAPH에서 그래픽 믹싱 개념을 처음 제안한 신급자님. 관심 있으신 분들은 바이두 부탁드려요~
위 사진을 검증하는 예시를 작성해주세요:
자, 위를 검증하는 예시를 작성해보겠습니다. 그림. 다양한 모드를 수정하여 결과를 비교하고 분석해보세요!
코드 구현:
1단계: 먼저 화면 너비와 높이를 가져오는 도구 클래스를 작성해 보겠습니다! ScreenUtil.java:
/** * Created by Jay on 2015/10/23 0023. */ public class ScreenUtil { /** * 获取屏幕宽高,sdk17后不建议采用 * * @param context */ public static int[] getScreenHW(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); Display display = manager.getDefaultDisplay(); int width = display.getWidth(); int height = display.getHeight(); int[] HW = new int[] { width, height }; return HW; } /** * 获取屏幕宽高,建议采用 * * @param context */ public static int[] getScreenHW2(Context context) { WindowManager manager = (WindowManager) context.getSystemService(Context.WINDOW_SERVICE); DisplayMetrics dm = new DisplayMetrics(); manager.getDefaultDisplay().getMetrics(dm); int width = dm.widthPixels; int height = dm.heightPixels; int[] HW = new int[] { width, height }; return HW; } /** * 获取屏幕的宽度 * * @param context * @return */ public static int getScreenW(Context context) { return getScreenHW2(context)[0]; } /** * 获取屏幕的高度 * * @param context * @return */ public static int getScreenH(Context context) { return getScreenHW2(context)[1]; } }
2단계: 사용자 정의 View 클래스를 작성하고 여기에서 실험해 보세요! XfermodeView.java:
/** * Created by Jay on 2015/10/23 0023. */ public class XfermodeView extends View { private PorterDuffXfermode pdXfermode; //定义PorterDuffXfermode变量 //定义MODE常量,等下直接改这里即可进行测试 private static PorterDuff.Mode PD_MODE = PorterDuff.Mode.ADD; private int screenW, screenH; //屏幕宽高 private int width = 200; //绘制的图片宽高 private int height = 200; private Bitmap srcBitmap, dstBitmap; //上层SRC的Bitmap和下层Dst的Bitmap public XfermodeView(Context context) { this(context, null); } public XfermodeView(Context context, AttributeSet attrs) { super(context, attrs); screenW = ScreenUtil.getScreenW(context); screenH = ScreenUtil.getScreenH(context); //创建一个PorterDuffXfermode对象 pdXfermode = new PorterDuffXfermode(PD_MODE); //实例化两个Bitmap srcBitmap = makeSrc(width, height); dstBitmap = makeDst(width, height); } public XfermodeView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } //定义一个绘制圆形Bitmap的方法 private Bitmap makeDst(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFF26AAD1); c.drawOval(new RectF(0, 0, w * 3 / 4, h * 3 / 4), p); return bm; } //定义一个绘制矩形的Bitmap的方法 private Bitmap makeSrc(int w, int h) { Bitmap bm = Bitmap.createBitmap(w, h, Bitmap.Config.ARGB_8888); Canvas c = new Canvas(bm); Paint p = new Paint(Paint.ANTI_ALIAS_FLAG); p.setColor(0xFFFFCE43); c.drawRect(w / 3, h / 3, w * 19 / 20, h * 19 / 20, p); return bm; } @Override protected void onDraw(Canvas canvas) { Paint paint = new Paint(); paint.setFilterBitmap(false); paint.setStyle(Paint.Style.FILL); canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2, (screenH / 2 - height) / 2, paint); canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3, (screenH / 2 - height) / 2, paint); //创建一个图层,在图层上演示图形混合后的效果 int sc = canvas.saveLayer(0, 0, screenW, screenH, null, Canvas.MATRIX_SAVE_FLAG | Canvas.CLIP_SAVE_FLAG | Canvas.HAS_ALPHA_LAYER_SAVE_FLAG | Canvas.FULL_COLOR_LAYER_SAVE_FLAG | Canvas.CLIP_TO_LAYER_SAVE_FLAG); canvas.drawBitmap(dstBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2, (screenH / 2 - height) / 2, paint); //绘制i //设置Paint的Xfermode paint.setXfermode(pdXfermode); canvas.drawBitmap(srcBitmap, (screenW / 3 - width) / 2 + screenW / 3 * 2, (screenH / 2 - height) / 2, paint); paint.setXfermode(null); // 还原画布 canvas.restoreToCount(sc); } }
코드가 복잡해 보이지만 그렇지 않습니다. 화면 너비와 높이를 가져온 다음 직사각형과 원을 그립니다. 위치를 계산한 후 하위 레이어(고정 쓰기 방식)를 설정하고 하위 브러시 setXfermode를 설정한 다음 그냥 캔버스에 그린 것일 뿐인데, 그리는 위치의 계산이 이해가 안 될 수도 있습니다. 실제로는 위치를 어떻게 결정하지? 괜찮을 거예요! 그럼 결과를 하나씩 살펴보겠습니다. PD_MODE 값을 수정하고 다른 모드로 설정하기만 하면 됩니다!
작업 렌더링:
1) PorterDuff.Mode.ADD:
Saturation overlay
2) PorterDuff.Mode.CLEAR:
그림이 캔버스에 제출되지 않습니다. 결과는... 왜인지는 모르겠지만, 정상입니다 아무것도...
3) PorterDuff.Mode.DARKEN:
두 레이어의 모든 영역을 가져오고 교차 부분의 색상을 깊게 만듭니다.
4) PorterDuff.Mode.DST:
유지만 대상 이미지의 알파와 색상이므로 대상 이미지만 그려집니다.
5) PorterDuff.Mode.DST_ATOP:
원본 이미지와 대상 이미지가 교차하는 곳에 대상 이미지가 그려지고, 원본 이미지가 그려집니다.
6) PorterDuff.Mode.DST_IN:
둘이 교차하는 곳에 대상 이미지를 그리면 원본 이미지의 투명도에 따라 그리기 효과가 영향을 받습니다
7) PorterDuff.Mode.DST_OUT :
교차하지 않는 곳에 대상 이미지를 그립니다.
8) PorterDuff.Mode.DST_OVER:
대상 이미지는 위에 그려집니다.
9) PorterDuff.Mode.LIGHTEN:
모든 영역을 차지합니다. 두 레이어를 겹쳐서 교차 색상을 켜세요
10) PorterDuff.Mode.MULTIPLY:
두 레이어를 겹쳐서 레이어의 교차 색상을 겹칩니다
11) PorterDuff.Mode.OVERLAY:
overlay
12) PorterDuff.Mode.SCREEN:
두 레이어의 모든 영역을 가져오면 교차 부분이 투명해집니다
13 ) PorterDuff.Mode.SRC:
소스 이미지의 알파와 색상만 유지하므로 소스만 이미지가 그려집니다
... 그림 16) PorterDuff.Mode.SRC_OUT: 교차하지 않는 곳에 원본 이미지를 그립니다. 17) PorterDuff.Mode.SRC_OVER: 위에 원본 이미지를 그립니다. 18) PorterDuff. Mode.XOR: 소스 및 대상 이미지는 분리된 장소에 있는 그대로 그려집니다.이 섹션의 샘플 코드 다운로드:
PorterDuffXfermodeDemo.zip
이 섹션 요약:글쎄 , 이 섹션에서는 18가지 PorterDuff.Mode의 다양한 효과를 확인하기 위해 간단한 뷰를 작성했습니다. 시간이 많이 걸리긴 하지만 독자들에게는 확실히 훨씬 더 명확해 보이죠~ 물론 이것은 단지 예비적인 통찰력일 뿐입니다! 의
PorterDuff.Mode
는 사용자 정의 컨트롤에 매우 중요합니다! 이 섹션에서는 예비적인 이해를 가졌습니다. 다음 섹션에서는 연습할 몇 가지 예를 선택하겠습니다.
PorterDuff.Mode에 대한 더 자세한 소개를 보려면 다음을 참조하세요.Android Paint의 setXfermode PorterDuffXfermode 설명
, 다른 사람들이 쓴 좋은 글! 그럼 됐고 내일 아침에 신체검사를 하고 오늘은 이것까지 쓰겠습니다~