W3Cschool
恭喜您成為首批注冊用戶
獲得88經(jīng)驗(yàn)值獎勵
上節(jié)我們寫了關(guān)于Xfermode與PorterDuff使用的第一個例子:圓角&圓形圖片ImageView的實(shí)現(xiàn), 我們體會到了PorterDuff.Mode.DST_IN給我們帶來的好處,本節(jié)我們繼續(xù)來寫例子練練手, 還記得8.3.2 繪圖類實(shí)戰(zhàn)示例給大家?guī)淼陌蔚裘琅路膶?shí)現(xiàn)嗎?
當(dāng)時我們的實(shí)現(xiàn)方案是,將手指觸碰區(qū)域附近的20*20個像素點(diǎn)設(shè)置為透明,效果圖是這樣的:
不知道你有沒有發(fā)現(xiàn)一個問題,我們擦美女衣服的時候,擦拭的時候都是方塊的,但是我們畫圖板 畫圖的時候,劃線都是很平滑的,有沒有辦法將兩者結(jié)合起來,我們擦衣服時也是圓滑的呢? 答案肯定是有的,就是使用Xfermode咯!本節(jié)我們使用另一個模式,DST_OUT模式! 在不相交的地方繪制目標(biāo)圖
如果你忘記了某個模式或者連18種模式都沒見過的話,那么請移步: Android基礎(chǔ)入門教程——8.3.5 Paint API之—— Xfermode與PorterDuff詳解(二) 另外,還是要貼下PorterDuff.Mode的效果圖:
嗯,話不多說,開始本節(jié)內(nèi)容~
要實(shí)現(xiàn)的效果圖:
嗯,不知道你看了那個Gif圖多少次了呢?不知道圖中是否適合大家的口味,小豬 是從別人的APP上扒下來的,別問我番號或者留郵箱什么的,我什么都不知道~找番什么的, 問群里的老司機(jī)——基神吧,好的,我們來分析下實(shí)現(xiàn)流程吧~
- 我們來說說原理,其實(shí)就是兩個Bitmap,一前一后,前面的是穿著衣服的,后面的是沒穿衣服的, 然后通過一個Path來記錄用戶繪制出來的圖形,然后為我們的畫筆設(shè)置DST_OUT的模式,那么 與Path重疊部分的DST(目標(biāo)圖),就是穿著衣服的圖,會變成透明!好噠,很簡單! 我們再慢慢細(xì)化!
- 首先我們需要兩個Bitmap,用來存儲前后兩張圖片,這里我們讓兩個Bitmap都全屏!
- 接著設(shè)置下畫筆,圓角,筆寬,抗鋸齒等!
- 再接著定義一個畫Path,即用戶繪制區(qū)域的方法,設(shè)置Xfermode后畫區(qū)域而已!
- 然后重寫onTouchEvent方法,這部分和之前的自定義畫圖板是一樣的!
- 最后重寫onDraw()方法,先繪制背景圖片,調(diào)用用戶繪制區(qū)域的方法,再繪制前景圖片!
可能看上去有點(diǎn)復(fù)雜,其實(shí)不然,代碼超簡單的說~
直接就一個自定義View——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);
//畫筆相關(guān)的設(shè)置
mPaint.setAntiAlias(true);
mPaint.setDither(true);
mPaint.setStyle(Paint.Style.STROKE);
mPaint.setStrokeJoin(Paint.Join.ROUND); // 圓角
mPaint.setStrokeCap(Paint.Cap.ROUND); // 圓角
mPaint.setStrokeWidth(80); // 設(shè)置畫筆寬
}
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>
好的,本節(jié)我們寫了Xfermode與PorterDuff的另一個實(shí)戰(zhàn)例子——手撕美女衣服的Demo,相比起我們之前 那種撕美女衣服(讓觸摸點(diǎn)附近20*20的像素點(diǎn)變成透明)的方式斯文多了~代碼也簡單很多是吧,有沒有 體會到Android圖像混排Xfermode給我們帶來的好處,或者對于自定義控件的重要性!嗯,還等什么, 打開你的IDE,把代碼擼一遍,嘗嘗手撕美女衣服的快感吧~
Copyright©2021 w3cschool編程獅|閩ICP備15016281號-3|閩公網(wǎng)安備35020302033924號
違法和不良信息舉報電話:173-0602-2364|舉報郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號
聯(lián)系方式:
更多建議: