Paint API - Xfermode 및 PorterDuff에 대한 자세한 설명(4)


이 섹션 소개:

이전 섹션에서 우리는 Xfermode 및 PorterDuff를 사용하는 첫 번째 예인 둥근 및 원형 이미지 ImageView의 구현에 대해 썼습니다. 우리는 PorterDuff.Mode.DST_IN이 우리에게 가져온 이점을 깨달았습니다. 이 섹션에서는 연습을 위한 예제를 계속 작성하겠습니다. 8.3.2 실제 사례 그리기 에서 가져온 아름다운 여성의 옷을 벗기는 구현을 아직도 기억하시나요?

1.gif

당시 우리의 구현 계획은 손가락 터치 영역 근처를 20*20픽셀로 설정하여 투명하게 만드는 것이었습니다.

2.gif

아주 아름다운 부분을 발견하셨는지 모르겠습니다. 여자옷은 닦을 땐 다 정사각형인데, 도화지를 그리면 다 똑같아. 그릴 때 선이 엄청 매끄러워요. 옷을 닦을 때 선이 매끄러워지도록 둘을 합치는 방법이 있나요? 대답은 확실히 그렇습니다. Xfermode를 사용하십시오! 이 섹션에서는 또 다른 모드인 DST_OUT 모드를 사용합니다! 분리된 장소에 대상 이미지 그리기

3.png

특정 모드를 잊어버렸거나 18개 모드도 본 적이 없다면 다음으로 이동하세요. Android 기본 입문 튜토리얼 - 8.3.5 Paint API - Xfermode PorterDuff에 대한 자세한 설명(2) 또한 PorterDuff.Mode의 렌더링을 게시하고 싶습니다.

4.png

자, 더 이상 고민하지 말고 이 섹션을 시작하겠습니다~


1 실현될 렌더링 및 구현 프로세스 분석:

렌더링 달성:

5.gif

7.gif글쎄요, 그 GIF를 몇 번이나 보셨는지 모르겠어요. 사진이 다들 입맛에 맞을지 모르겠네요 샤오주 다른 사람의 APP에서 스크랩했습니다. 제게 전화번호나 이메일 주소를 묻지 마세요. 뭔가를 찾고 있습니다. 그룹의 베테랑 운전자에게 물어보세요 - 지센, 알았어 구현 과정을 분석해 봅시다 ~

  • 실제로는 두 개의 비트맵인데 앞에 있는 사람은 옷을 입고 있고 뒤에 있는 사람은 옷을 입지 않은 상태입니다. 그런 다음 경로를 사용하여 사용자가 그린 그래픽을 기록한 다음 브러시에 대해 DST_OUT 모드를 설정한 다음 옷을 입고 있는 이미지인 Path와 겹치는 DST(대상 이미지)가 투명해집니다! 좋아요, 쉽습니다! 천천히 다듬어보자!
  • 먼저 앞면과 뒷면 사진을 저장하려면 두 개의 비트맵이 필요합니다. 여기서 두 비트맵을 전체 화면으로 만듭니다.
  • 그런 다음 브러시, 둥근 모서리, 펜 너비, 앤티앨리어싱 등을 설정하세요!
  • 그런 다음 사용자가 영역을 그리는 방법인 그리기 경로를 정의하고 Xfermode를 설정한 후 영역을 그리면 됩니다!
  • 그런 다음 onTouchEvent 메소드를 다시 작성하세요. 이 부분은 이전 사용자 정의 드로잉 보드와 동일합니다!
  • 마지막으로 onDraw() 메서드를 다시 작성하고, 먼저 배경 이미지를 그리고, 사용자가 영역을 그리는 메서드를 호출한 다음, 전경 이미지를 그립니다!

조금 복잡해 보일 수도 있지만 사실 코드는 매우 간단합니다~


2. 코드 구현:

커스텀 뷰——StripMeiZi.java

/**
 * Created by Jay on 2015/10/25 0025.
 */
public class StripMeiZi extends View{

    private Paint mPaint = new Paint();
    private Path mPath = new Path();
    private Canvas mCanvas;
    private Bitmap mBeforeBitmap;
    private Bitmap mBackBitmap;
    private int mLastX,mLastY;
    private int screenW, screenH; //屏幕宽高
    private Xfermode mXfermode = new PorterDuffXfermode(PorterDuff.Mode.DST_OUT);


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

    public StripMeiZi(Context context, AttributeSet attrs) {
        super(context, attrs);
        screenW = ScreenUtil.getScreenW(context);
        screenH = ScreenUtil.getScreenH(context);
        init();
    }


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

    private void init() {
        //背后图片,这里让它全屏
        mBackBitmap = BitmapFactory.decodeResource(getResources(), R.mipmap.meizi_back);
        mBackBitmap = Bitmap.createScaledBitmap(mBackBitmap, screenW, screenH, false);
        //前面的图片,并绘制到Canvas上
        mBeforeBitmap = Bitmap.createBitmap(screenW, screenH, Bitmap.Config.ARGB_8888);
        mCanvas = new Canvas(mBeforeBitmap);
        mCanvas.drawBitmap(BitmapFactory.decodeResource(getResources(),
                R.mipmap.meizi_before), null, new RectF(0, 0, screenW, screenH), null);
        //画笔相关的设置
        mPaint.setAntiAlias(true);
        mPaint.setDither(true);
        mPaint.setStyle(Paint.Style.STROKE);
        mPaint.setStrokeJoin(Paint.Join.ROUND); // 圆角
        mPaint.setStrokeCap(Paint.Cap.ROUND); // 圆角
        mPaint.setStrokeWidth(80);    // 设置画笔宽
    }

    private void drawPath() {
        mPaint.setXfermode(mXfermode);
        mCanvas.drawPath(mPath, mPaint);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawBitmap(mBackBitmap, 0, 0, null);
        drawPath();
        canvas.drawBitmap(mBeforeBitmap, 0, 0, null);
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        int action = event.getAction();
        int x = (int) event.getX();
        int y = (int) event.getY();
        switch (action)
        {
            case MotionEvent.ACTION_DOWN:
                mLastX = x;
                mLastY = y;
                mPath.moveTo(mLastX, mLastY);
                break;
            case MotionEvent.ACTION_MOVE:

                int dx = Math.abs(x - mLastX);
                int dy = Math.abs(y - mLastY);

                if (dx > 3 || dy > 3)
                    mPath.lineTo(x, y);

                mLastX = x;
                mLastY = y;
                break;
        }
        invalidate();
        return true;
    }
}

레이아웃 코드activity_main. xml:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".MainActivity">

    <com.jay.xfermodedemo2.StripMeiZi
        android:layout_width="match_parent"
        android:layout_height="match_parent"/></RelativeLayout>

3. 코드 샘플 다운로드:

XfermodeDemo2.zip


이 섹션 요약:

좋습니다. 이 섹션에서는 Xfermode 및 PorterDuff의 또 다른 실제 예제를 작성했습니다. 뷰티 의류, 이전 제품에 비해 미인의 옷을 찢는 방법(터치포인트 근처의 20*20픽셀을 투명하게 만드는 방법)이 훨씬 우아하네요~ 코드도 훨씬 간단하죠? Android 이미지 셔플링 Xfermode가 우리에게 제공하는 이점 또는 사용자 정의 컨트롤의 중요성을 인식하십시오! 글쎄, 당신은 무엇을 기다리고 있습니까? IDE를 열고 코드를 플레이하며 아름다운 여성의 옷을 찢는 즐거움을 맛보세요~6.gif