Android自定義View_BitmapShader實現望遠鏡效果

日拱一卒,功不唐捐

一、背景

這個特效來源於有一天逛網站的時候,一家網站實現了這樣的一個效果:在你向下滾動頁面的時候,他的背景的圖片隨着你的滑動,以窗口的方式展示着圖片的某一部分。瀏覽完就想着以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
公衆號:小猿說

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章