日拱一卒,功不唐捐
一、背景
這個特效來源於有一天逛網站的時候,一家網站實現了這樣的一個效果:在你向下滾動頁面的時候,他的背景的圖片隨着你的滑動,以窗口的方式展示着圖片的某一部分。瀏覽完就想着以Android的方式能不能實現,也就演變成了以下的效果。
二、知識點BitmapShader
【官方】Shader用於繪製位圖作爲紋理。位圖可以設置模式爲重複或鏡像或平鋪。
簡單來說,Shader可以用來實現一些漸變,反轉,鏡像,重複等效果。本文的效果核心使用的是Shader中的BitmapShader——位圖Shader。
BitmapShader(Bitmap bitmap, Shader.TileMode tileX, Shader.TileMode tileY)
從構造方法可以看出,第一個參數爲位圖bitmap,第二個和第三個參數分別爲橫方向和縱方向的平鋪模式。
平鋪模式有如下幾種模式:
- CLAMP :拉伸,水平拉伸圖片左右方向最後一個像素,,垂直拉伸圖片上下方向的最後一個像素。
- MIRROR:鏡像,水平和垂直方向重複圖像,交替鏡像,使相鄰的圖像始終相連。
- REPEAT:重複,水平和垂直方向不斷重複圖片。
三、基本思路
1、創建一張圖片,將畫筆設置爲帶有圖像填充功能;
2、根據獲取手指所點擊位置的座標,根據獲得的座標繪製圓形或者其他圖形。
四、實現
從上述基本思路來看,步驟還是很簡單,那麼接下來分析實現的代碼。
mPaint = new Paint();
mBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.photo2);
首先就是初始化畫筆和創建一張位圖。接下來爲核心內容。
mPaint.setShader(new BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP));
canvas.drawCircle(400,400,300,mPaint);
BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)新創建一個BitmapShader,並將水平和垂直方向的平鋪模式設置爲CLAMP拉伸模式,將BitmapShader屬性設置給畫筆,使畫筆具有圖像填充功能,這是後面畫筆可以繪製出一個帶有圖片的圓形的原因。接着利用Canvas在座標(400,400)處繪製出一個半徑爲300的圓形。
目前基本的繪製已經結束,運行代碼可以看出會有圓形圖片在界面顯示,如下圖:
從上面的圖片來看,是不是發現其實這就是一個圓形的頭像,到這裏我們可以想到前面有一篇Android自定義菱形圖片使用PorterDuffXfermode的相關屬性繪製菱形的頭像,其實這裏我們也可以使用BitmapShader進行操作,代碼相比較更加簡潔。
目前實現的是靜態的圖像,接下來實現隨着手指動態移動的效果。
private float mTouchEventY = -1;
private float mTouchEventX = -1;
......
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mTouchEventX = event.getX();
mTouchEventY = event.getY();
return true;
case MotionEvent.ACTION_MOVE:
mTouchEventX = event.getX();
mTouchEventY = event.getY();
postInvalidate();
break;
}
postInvalidate();
return super.onTouchEvent(event);
}
首先我們創建兩個全局變量mTouchEventX,mTouchEventY。在onTouchEvent事件中,手指MotionEvent.ACTION_DOWN的時候,動態獲取手指的位置,在ACTION_DOWN的代碼中記得return true,這涉及到事件的分發機制,當return false時,代表手指的down事件未完成,那麼事件將不會繼續向下傳遞,也就是說ACTION_DOWN動作後的ACTION_MOVE是不會觸發的。
同樣的,我們在MotionEvent.ACTION_MOVE中也動態獲取手指的位置,也就是隨着手指動態調整圓形的位置。
最後在Canvas繪製圓形的時候,將獲取到的位置設置進去,隨着手指的不斷移動,不斷獲取到位置值,也就實現了動態繪製圖像的效果。
canvas.drawCircle(mTouchEventX,mTouchEventY,300,mPaint);
五、最後
在上述的過程中,發現BitmapShader可以很容易的實現不規則頭像。另外,上述也只使用了BitmapShader的拉伸模式,還有鏡像和重複模式可以實現更多的特效,有待發掘。
文章同步個人博客:https://fuusy.github.io
項目地址:https://github.com/fuusy/ShaderTelescope.git
公衆號:小猿說