陰影製作效果 ShadowLayout 布局實現(讓控制項實現立體效果),shadowlayout控制項

來源:互聯網
上載者:User

陰影製作效果 ShadowLayout 布局實現(讓控制項實現立體效果),shadowlayout控制項
效果


第二張和第三張圖是加入了陰影製作效果的,是不是覺得立體感很強,感覺圖片是浮在螢幕上。這個效果也可以用Google 提供擴充包下的CardView控制項來實現,而這篇文章是帶大家自己來實現這樣一個效果。

原理

我們仔細觀察,可以發現,有帶陰影製作效果的圖和沒帶陰影製作效果的圖,其實就一個地方不同,就是在圖片的底下繪製了陰影製作效果,而圖片的大小都沒變。所以我們要做的就是給子 View 繪製陰影。那麼陰影部分怎麼繪製呢?這裡是整個效果實現的一個痛點;陰影部分其實就是一張 bitmap 圖片,而接下來的工作就是如何產生一張這樣效果的 bitmap 圖,還有就是 bitmap 圖片繪製位置的確定。

實現

1、陰影製作效果的 bitmap 圖片的產生
最簡單的辦法叫美工做一張,我們把他轉化成.9圖片,這是一種方法;還有一種方法就是用代碼產生這樣一張 bitmap,要實現這樣的效果,我們需要用到 Paint 畫筆中的一個屬性

public MaskFilter setMaskFilter(MaskFilter maskfilter) {//...}

這個 MaskFilter有一個子類BlurMaskFilter就能實現這樣的效果,一般把它叫為毛半透明效果。這個類的實現需要傳兩個參數

public BlurMaskFilter(float radius, Blur style) {        //...    }

radius:漸層效果的距離。

style:模式,這裡有四中模式

    public enum Blur {        /**         * Blur inside and outside the original border.         */        NORMAL(0),        /**         * Draw solid inside the border, blur outside.         */        SOLID(1),        /**         * Draw nothing inside the border, blur outside.         */        OUTER(2),        /**         * Blur inside the border, draw nothing outside.         */        INNER(3);        Blur(int value) {            native_int = value;        }        final int native_int;    }

這幾種模式到底是怎麼的呢?來看看下面那張圖

以形是通過

    public void drawRect(RectF rect, Paint paint) {        ;    }

看到這張圖加上上面幾種模式的註解,應該很清楚了。
這裡有一個注意點是:我們繪製矩形的時候,如果沒有設定這種模糊效果,這繪製的圖形的大小就是矩形的大小,如果繪製了模糊效果,則圖形的大小需要加上執行個體化BlurMaskFilter時候的radius,就是漸層的距離。
建立 bitmap 的代碼如下:

        //設定畫筆的 style        mPaint.setStyle(Paint.Style.FILL);        //設定畫筆的模糊效果        mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));        //設定畫筆的顏色        mPaint.setColor(Color.BLACK);        //建立 bitmap 圖片        mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888);        //綁定到畫布上        Canvas canvas = new Canvas(mShadowBitmap);        //讓畫布平移,這裡為什麼要平移,看了前面圖片就知道        canvas.translate(BLUR_WIDTH,BLUR_WIDTH);        //繪製陰影製作效果        canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint);

2、bitmap 圖片繪製位置的確定
bitmap 的繪製,是放在

protected void dispatchDraw(Canvas canvas) {//...}

這裡有各地方需要注意,需要先繪製 bitmap,在調用

super.dispatchDraw(canvas);

為什嗎?很好理解了,因為super.dispatchDraw(canvas);是分發繪製機制,Layout 的所有子類的繪製都需要通過它來分發,如果先繪製子類,那麼 bitmap 陰影部分就會顯示在子類的上面,會把子類覆蓋。
代碼如下:

    @Override    protected void dispatchDraw(Canvas canvas) {        int N = getChildCount() ;        for (int i = 0; i < N ; i ++){            View view = getChildAt(i) ;            if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE||                    view.getAlpha() == 0){                continue;            }            int left = view.getLeft() ;            int top = view.getTop() ;            /*儲存畫布的位置*/            canvas.save() ;            /*平移畫布*/            canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80);            /*設定繪製陰影畫筆的透明度*/            mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth)));            /*擷取陰影的繪製寬度*/            mDesRecF.right = view.getWidth() ;            /*擷取陰影的繪製高度*/            mDesRecF.bottom = view.getHeight() ;            /*繪製陰影*/            canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint);            /*還原畫筆*/            canvas.restore();        }        super.dispatchDraw(canvas);    }

到這裡整個效果的 Layout 布局就寫完了,代碼非常簡潔,總共100行代碼不到,索性就全部貼出來吧

/** * Created by moon.zhong on 2015/3/25. */public class ShadowLayout extends RelativeLayout {    private float mDepth = 0.5f;    private Bitmap mShadowBitmap;    private Paint mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);    private final int BLUR_WIDTH = 5 ;    private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ;    private RectF mDesRecF = new RectF(0,0,150,150) ;    private int mRadius = 6 ;    private Paint mAlphaPaint ;    public ShadowLayout(Context context) {        super(context);        initView(context);    }    public ShadowLayout(Context context, AttributeSet attrs) {        super(context, attrs);        initView(context);    }    public ShadowLayout(Context context, AttributeSet attrs, int defStyleAttr) {        super(context, attrs, defStyleAttr);        initView(context);    }    private void initView(Context context) {        setWillNotDraw(false);        //設定畫筆的 style        mPaint.setStyle(Paint.Style.FILL);        //設定畫筆的模糊效果        mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));        //設定畫筆的顏色        mPaint.setColor(Color.BLACK);        //建立 bitmap 圖片        mShadowBitmap = Bitmap.createBitmap(mOriginRect.width(), mOriginRect.height(), Bitmap.Config.ARGB_8888);        //綁定到畫布上        Canvas canvas = new Canvas(mShadowBitmap);        //讓畫布平移,這裡為什麼要平移,看了前面圖片就知道        canvas.translate(BLUR_WIDTH,BLUR_WIDTH);        //繪製陰影製作效果        canvas.drawRoundRect(mDesRecF, mRadius, mRadius, mPaint);        mAlphaPaint = new Paint(Paint.ANTI_ALIAS_FLAG) ;    }    public void setDepth(float depth){        mDepth = depth ;        invalidate();    }    @Override    protected void dispatchDraw(Canvas canvas) {        int N = getChildCount() ;        for (int i = 0; i < N ; i ++){            View view = getChildAt(i) ;            if (view.getVisibility() == GONE ||view.getVisibility() == INVISIBLE||                    view.getAlpha() == 0){                continue;            }            int left = view.getLeft() ;            int top = view.getTop() ;            /*儲存畫布的位置*/            canvas.save() ;            /*平移畫布*/            canvas.translate(left + (1-mDepth)*80,top + (1-mDepth)*80);            /*設定繪製陰影畫筆的透明度*/            mAlphaPaint.setAlpha((int) (125 + 100 * (mDepth)));            /*擷取陰影的繪製寬度*/            mDesRecF.right = view.getWidth() ;            /*擷取陰影的繪製高度*/            mDesRecF.bottom = view.getHeight() ;            /*繪製陰影*/            canvas.drawBitmap(mShadowBitmap, mOriginRect, mDesRecF, mAlphaPaint);            /*還原畫筆*/            canvas.restore();        }        super.dispatchDraw(canvas);    }}

再來看一下動態

總結

整體實現不是特別難,最主要的是 Paint類中 的

 mPaint.setMaskFilter(new BlurMaskFilter(BLUR_WIDTH, BlurMaskFilter.Blur.NORMAL));

在建立 bitmap 的時候,bitmap 的大小一定要加上2倍的BLUR_WIDTH也就是

private final Rect mOriginRect = new Rect(0,0,150+ 2*BLUR_WIDTH,150+2*BLUR_WIDTH) ;

至於為什麼前面已經講了。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.