Chế độ xem hình ảnh tùy chỉnh với bóng đổ


98

Được rồi, tôi đã đọc và tìm kiếm xung quanh, và bây giờ tôi đang đập đầu vào tường để cố gắng tìm ra điều này. Đây là những gì tôi có cho đến nay:

package com.pockdroid.sandbox;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.widget.ImageView;

public class ShadowImageView extends ImageView {

private Rect mRect;
private Paint mPaint;

public ShadowImageView(Context context)
{
    super(context);
    mRect = new Rect();
    mPaint = new Paint();
    mPaint.setAntiAlias(true);
    mPaint.setShadowLayer(2f, 1f, 1f, Color.BLACK);
}

@Override
protected void onDraw(Canvas canvas) 
{
    Rect r = mRect;
    Paint paint = mPaint;

    canvas.drawRect(r, paint);
    super.onDraw(canvas);
}

@Override
protected void onMeasure(int w, int h)
{
    super.onMeasure(w,h);
    int mH, mW;
    mW = getSuggestedMinimumWidth() < getMeasuredWidth()? getMeasuredWidth() : getSuggestedMinimumWidth();
    mH = getSuggestedMinimumHeight() < getMeasuredHeight()? getMeasuredHeight() : getSuggestedMinimumHeight();
    setMeasuredDimension(mW + 5, mH + 5);
}

}

"+5" trong các phép đo ở đó là tạm thời; Từ những gì tôi hiểu, tôi sẽ cần thực hiện một số phép toán để xác định kích thước mà bóng đổ thêm vào canvas, phải không?

Nhưng khi tôi sử dụng cái này:

public View getView(int position, View convertView, ViewGroup parent) {
    ShadowImageView sImageView;
    if (convertView == null) {
        sImageView = new ShadowImageView(mContext);
        GridView.LayoutParams lp = new GridView.LayoutParams(85, 85);
        sImageView.setLayoutParams(lp);

        sImageView.setScaleType(ImageView.ScaleType.CENTER);
        sImageView.setPadding(5,5,5,5);
    } else {
        sImageView = (ShadowImageView) convertView;
    }

    sImageView.setImageBitmap(bitmapList.get(position));
    return sImageView;
}

trong ImageView của mình, tôi vẫn chỉ nhận được ImageView bình thường khi chạy chương trình.

Có suy nghĩ gì không? Cảm ơn.

CHỈNH SỬA: Vì vậy, tôi đã nói chuyện với RomainGuy một số trong kênh IRC và bây giờ tôi đã làm việc với các hình ảnh hình chữ nhật đơn giản với mã bên dưới. Mặc dù vậy, nó vẫn sẽ không vẽ bóng trực tiếp đến độ trong suốt của bitmap của tôi, vì vậy tôi vẫn đang làm việc trên đó.

@Override
protected void onDraw(Canvas canvas) 
{
    Bitmap bmp = BitmapFactory.decodeResource(getResources(), R.drawable.omen);
    Paint paint = new Paint();
    paint.setAntiAlias(true);
    paint.setShadowLayer(5.5f, 6.0f, 6.0f, Color.BLACK);
    canvas.drawColor(Color.GRAY);
    canvas.drawRect(50, 50, 50 + bmp.getWidth(), 50 + bmp.getHeight(), paint);
    canvas.drawBitmap(bmp, 50, 50, null);       
}

"nó hiện đang hoạt động đối với hình ảnh hình chữ nhật đơn giản" ... vì vậy nó không hoạt động đối với hình ảnh không phải hình chữ nhật, và sau đó tôi cho rằng nó cũng không hoạt động đối với hình ảnh 9patch, đúng không? Bạn có làm cho nó hoạt động được không? Vì phương pháp này của Romain Guy chưa phù hợp với tôi trong thử nghiệm của tôi.
Mathias Conradt

Hmm, câu hỏi thú vị. Tôi nghĩ rằng bạn có thể lấy Chế độ xem của mình bằng cách sử dụng 9-patch và bọc nó trong FrameLayout, và cung cấp cho FrameLayout làm nền 9-patch bóng đổ. Nhưng đúng vậy, nó chỉ hoạt động với hình ảnh hình chữ nhật, bởi vì không có cách nào để 9-patch tuân theo các đường viền trong suốt. Rất tiếc, tôi vẫn chưa tìm ra giải pháp tốt hơn, tuy nhiên, tôi đã không thực sự thử lại kể từ đó.
Kevin Coppock

Câu trả lời:


122

Được rồi, tôi không đoán trước được câu trả lời nào nữa cho câu trả lời này, vì vậy những gì tôi kết thúc bây giờ chỉ là một giải pháp cho hình ảnh chữ nhật. Tôi đã sử dụng NinePatch sau:

văn bản thay thế

cùng với phần đệm thích hợp trong XML:

<ImageView
        android:id="@+id/image_test"
        android:background="@drawable/drop_shadow"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:paddingLeft="6px"
        android:paddingTop="4px"
        android:paddingRight="8px"
        android:paddingBottom="9px"
        android:src="@drawable/pic1"
        />

để có được một kết quả khá tốt:

văn bản thay thế

Không lý tưởng, nhưng nó sẽ làm được.


17
Đừng quên lưu png dưới dạng drop_shadow.9.png.
NPike

1
Chà, tôi đã dành quá nhiều thời gian để cố gắng làm điều này trong mã. Giải pháp thanh lịch hơn nhiều!
Nik Reiman

Còn những hình ảnh cần điều chỉnh giới hạn xem thì sao?
StackOverflowed

Không cần sử dụng công cụ draw9patch nếu bạn thực hiện đúng.
Kevin Coppock

2
Bạn có thể tìm thêm một chút hướng dẫn từng bước tại đây: sapandiwakar.in/…
Bart Burg

105

Điều này được trích từ bài thuyết trình của Romain Guy tại Devoxx, pdf được tìm thấy ở đây .

Paint mShadow = new Paint(); 
// radius=10, y-offset=2, color=black 
mShadow.setShadowLayer(10.0f, 0.0f, 2.0f, 0xFF000000); 
// in onDraw(Canvas) 
canvas.drawBitmap(bitmap, 0.0f, 0.0f, mShadow);

Hi vọng điêu nay co ich.

LƯU Ý

  1. Đừng quên đối với Honeycomb trở lên, bạn cần phải gọi setLayerType(LAYER_TYPE_SOFTWARE, mShadow), nếu không bạn sẽ không thấy bóng của mình! (@Dmitriy_Boichenko)
  2. SetShadowLayerRất tiếc, không hoạt động với khả năng tăng tốc phần cứng nên nó làm giảm đáng kể hiệu suất (@Matt Wear) [1] [2]

Tôi chắc chắn sẽ thử điều này sau! Cảm ơn vì tệp PDF cũng giống như những thứ thú vị. Video trình bày này có sẵn trực tuyến để xem không?
Kevin Coppock

14
Đừng quên đối với Honeycomb trở lên, hãy gọi setLayerType (LAYER_TYPE_SOFTWARE, mShadow). Nếu không bạn sẽ không nhìn thấy bóng của mình.
Dmytro Boichenko

5
setShadowLayer rất tiếc không hoạt động với tính năng tăng tốc phần cứng.
Matt Wear

bạn cũng áp dụng Paint cho các hình dạng, vì vậy lớp bóng phù hợp với chúng. Tuy nhiên, nó sẽ không được áp dụng cho các 'lỗ' bên trong trong một hình dạng.
straya

4
Liên kết Devoxx đã chết
joao2fast4u

14

Tôi tin câu trả lời này từ UIFuel

<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">

     <!-- Drop Shadow Stack -->
     <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#00CCCCCC" />
        </shape>
    </item>
     <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#10CCCCCC" />
        </shape>
    </item>
     <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#20CCCCCC" />
        </shape>
    </item>
     <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#30CCCCCC" />
        </shape>
    </item>
    <item>
        <shape>
            <padding android:top="1dp" android:right="1dp" android:bottom="1dp" android:left="1dp" />
            <solid android:color="#50CCCCCC" />
        </shape>
    </item>

    <!-- Background -->
    <item>
    <shape>
            <solid android:color="@color/white" />
        <corners android:radius="3dp" />
    </shape>
    </item>
</layer-list>

12

Giải pháp bẩn thỉu của tôi:

private static Bitmap getDropShadow3(Bitmap bitmap) {

    if (bitmap==null) return null;
    int think = 6;
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    int newW = w - (think);
    int newH = h - (think);

    Bitmap.Config conf = Bitmap.Config.ARGB_8888;
    Bitmap bmp = Bitmap.createBitmap(w, h, conf);
    Bitmap sbmp = Bitmap.createScaledBitmap(bitmap, newW, newH, false);

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Canvas c = new Canvas(bmp);

    // Right
    Shader rshader = new LinearGradient(newW, 0, w, 0, Color.GRAY, Color.LTGRAY, Shader.TileMode.CLAMP);
    paint.setShader(rshader);
    c.drawRect(newW, think, w, newH, paint);

    // Bottom
    Shader bshader = new LinearGradient(0, newH, 0, h, Color.GRAY, Color.LTGRAY, Shader.TileMode.CLAMP);
    paint.setShader(bshader);
    c.drawRect(think, newH, newW  , h, paint);

    //Corner
    Shader cchader = new LinearGradient(0, newH, 0, h, Color.LTGRAY, Color.LTGRAY, Shader.TileMode.CLAMP);
    paint.setShader(cchader);
    c.drawRect(newW, newH, w  , h, paint);


    c.drawBitmap(sbmp, 0, 0, null);

    return bmp;
}

kết quả: nhập mô tả hình ảnh ở đây


nó cho bóng xanh luôn!
Animesh Mangla,

8

Của bạn đây. Đặt nguồn của ImageView tĩnh trong xml hoặc động trong mã.

Bóng ở đây là màu trắng.

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="wrap_content" android:layout_height="wrap_content">

    <View android:layout_width="wrap_content" android:layout_height="wrap_content"
        android:background="@android:color/white" android:layout_alignLeft="@+id/image"
        android:layout_alignRight="@id/image" android:layout_alignTop="@id/image"
        android:layout_alignBottom="@id/image" android:layout_marginLeft="10dp"
        android:layout_marginBottom="10dp" />

    <ImageView android:id="@id/image" android:layout_width="wrap_content"
        android:layout_height="wrap_content" android:src="..."
        android:padding="5dp" />

</RelativeLayout>

Chắc chắn không phải thứ tôi đang tìm kiếm. Tôi muốn một bóng đổ được kết xuất thực tế mờ dần đến trong suốt; điều đó sẽ chỉ cho tôi một hộp màu trắng đằng sau hình ảnh của tôi.
Kevin Coppock

9
@kcoppock - không cần thiết phải phản đối câu trả lời này - nó thực sự không tệ như vậy.
Caspar Harmer

4

Tôi quản lý để áp dụng đường viền gradient bằng mã này ..

public static Bitmap drawShadow(Bitmap bitmap, int leftRightThk, int bottomThk, int padTop) {
    int w = bitmap.getWidth();
    int h = bitmap.getHeight();

    int newW = w - (leftRightThk * 2);
    int newH = h - (bottomThk + padTop);

    Bitmap.Config conf = Bitmap.Config.ARGB_8888;
    Bitmap bmp = Bitmap.createBitmap(w, h, conf);
    Bitmap sbmp = Bitmap.createScaledBitmap(bitmap, newW, newH, false);

    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Canvas c = new Canvas(bmp);

    // Left
    int leftMargin = (leftRightThk + 7)/2;
    Shader lshader = new LinearGradient(0, 0, leftMargin, 0, Color.TRANSPARENT, Color.BLACK, TileMode.CLAMP);
    paint.setShader(lshader);
    c.drawRect(0, padTop, leftMargin, newH, paint); 

    // Right
    Shader rshader = new LinearGradient(w - leftMargin, 0, w, 0, Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);
    paint.setShader(rshader);
    c.drawRect(newW, padTop, w, newH, paint);

    // Bottom
    Shader bshader = new LinearGradient(0, newH, 0, bitmap.getHeight(), Color.BLACK, Color.TRANSPARENT, TileMode.CLAMP);
    paint.setShader(bshader);
    c.drawRect(leftMargin -3, newH, newW + leftMargin + 3, bitmap.getHeight(), paint);
    c.drawBitmap(sbmp, leftRightThk, 0, null);

    return bmp;
}

hi vọng điêu nay co ich !


2

Điều này phù hợp với tôi ...

public class ShadowImage extends Drawable {

Bitmap bm;

@Override
public void draw(Canvas canvas) {

    Paint mShadow = new Paint();
    Rect rect = new Rect(0,0,bm.getWidth(), bm.getHeight());

    mShadow.setAntiAlias(true);
    mShadow.setShadowLayer(5.5f, 4.0f, 4.0f, Color.BLACK);

    canvas.drawRect(rect, mShadow);
    canvas.drawBitmap(bm, 0.0f, 0.0f, null);

}

public ShadowImage(Bitmap bitmap) {
    super();
    this.bm = bitmap;
} ... }

2

Đây là câu trả lời của Paul Burke :

public class ShadowImageView extends ImageView {

    public ShadowImageView(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public ShadowImageView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public ShadowImageView(Context context) {
        super(context);
    }

    private Paint createShadow() {
        Paint mShadow = new Paint();

        float radius = 10.0f;
        float xOffset = 0.0f;
        float yOffset = 2.0f;

        // color=black
        int color = 0xFF000000;
        mShadow.setShadowLayer(radius, xOffset, yOffset, color);


        return mShadow;
    }

    @Override
    protected void onDraw(Canvas canvas) {
        Paint mShadow = createShadow();
        Drawable d = getDrawable();
        if (d != null){
            setLayerType(LAYER_TYPE_SOFTWARE, mShadow);
            Bitmap bitmap = ((BitmapDrawable) getDrawable()).getBitmap();
            canvas.drawBitmap(bitmap, 0.0f, 0.0f, mShadow);
        } else {
            super.onDraw(canvas);
        }

    };

}

VIỆC CẦN LÀM: setLayerType(LAYER_TYPE_SOFTWARE, mShadow);chỉ thực thi nếu Cấp API> 10


Xin lỗi, các vòng lặp vô hạn được gọi bằng một lớp Realm
runloop

Tôi không thể cho đến khi câu hỏi được chỉnh sửa. Chỉ cần thực hiện bất kỳ thay đổi nhỏ nào, hãy cho tôi biết và sau đó tôi sẽ ủng hộ lại.
RunLoop 17/02/16

0

Tôi đã xây dựng dựa trên câu trả lời ở trên - https://stackoverflow.com/a/11155031/2060486 - để tạo bóng xung quanh TẤT CẢ các mặt ..

 private static final int GRAY_COLOR_FOR_SHADE = Color.argb(50, 79, 79, 79);

// this method takes a bitmap and draws around it 4 rectangles with gradient to create a
// shadow effect.
public static Bitmap addShadowToBitmap(Bitmap origBitmap) {
    int shadowThickness = 13; // can be adjusted as needed
    int bmpOriginalWidth = origBitmap.getWidth();
    int bmpOriginalHeight = origBitmap.getHeight();
    int bigW = bmpOriginalWidth + shadowThickness * 2; // getting dimensions for a bigger bitmap with margins
    int bigH = bmpOriginalHeight + shadowThickness * 2;
    Bitmap containerBitmap = Bitmap.createBitmap(bigW, bigH, Bitmap.Config.ARGB_8888);
    Bitmap copyOfOrigBitmap = Bitmap.createScaledBitmap(origBitmap, bmpOriginalWidth, bmpOriginalHeight, false);
    Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG);
    Canvas canvas = new Canvas(containerBitmap); // drawing the shades on the bigger bitmap
    //right shade - direction of gradient is positive x (width)
    Shader rightShader = new LinearGradient(bmpOriginalWidth, 0, bigW, 0, GRAY_COLOR_FOR_SHADE,
            Color.TRANSPARENT, Shader.TileMode.CLAMP);
    paint.setShader(rightShader);
    canvas.drawRect(bigW - shadowThickness, shadowThickness, bigW, bigH - shadowThickness, paint);
    //bottom shade - direction is positive y (height)
    Shader bottomShader = new LinearGradient(0, bmpOriginalHeight, 0, bigH, GRAY_COLOR_FOR_SHADE,
            Color.TRANSPARENT, Shader.TileMode.CLAMP);
    paint.setShader(bottomShader);
    canvas.drawRect(shadowThickness, bigH - shadowThickness, bigW - shadowThickness, bigH, paint);
    //left shade - direction is negative x
    Shader leftShader = new LinearGradient(shadowThickness, 0, 0, 0, GRAY_COLOR_FOR_SHADE,
            Color.TRANSPARENT, Shader.TileMode.CLAMP);
    paint.setShader(leftShader);
    canvas.drawRect(0, shadowThickness, shadowThickness, bigH - shadowThickness, paint);
    //top shade - direction is negative y
    Shader topShader = new LinearGradient(0, shadowThickness, 0, 0, GRAY_COLOR_FOR_SHADE,
            Color.TRANSPARENT, Shader.TileMode.CLAMP);
    paint.setShader(topShader);
    canvas.drawRect(shadowThickness, 0, bigW - shadowThickness, shadowThickness, paint);
    // starting to draw bitmap not from 0,0 to get margins for shade rectangles
    canvas.drawBitmap(copyOfOrigBitmap, shadowThickness, shadowThickness, null);
    return containerBitmap;
}

Thay đổi màu trong const khi bạn thấy phù hợp.


0

Sử dụng lớp này để vẽ bóng trên bitmap

public class ShadowGenerator {

    // Percent of actual icon size
    private static final float HALF_DISTANCE = 0.5f;
    public static final float BLUR_FACTOR = 0.5f/48;

    // Percent of actual icon size
    private static final float KEY_SHADOW_DISTANCE = 1f/48;
    public static final int KEY_SHADOW_ALPHA = 61;

    public static final int AMBIENT_SHADOW_ALPHA = 30;

    private static final Object LOCK = new Object();
    // Singleton object guarded by {@link #LOCK}
    private static ShadowGenerator sShadowGenerator;

    private  int mIconSize;

    private final Canvas mCanvas;
    private final Paint mBlurPaint;
    private final Paint mDrawPaint;
    private final Context mContext;

    private ShadowGenerator(Context context) {
        mContext = context;
        mIconSize = Utils.convertDpToPixel(context,63);
        mCanvas = new Canvas();
        mBlurPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
        mBlurPaint.setMaskFilter(new BlurMaskFilter(mIconSize * BLUR_FACTOR, Blur.NORMAL));
        mDrawPaint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FILTER_BITMAP_FLAG);
    }

    public synchronized Bitmap recreateIcon(Bitmap icon) {
        mIconSize = Utils.convertDpToPixel(mContext,3)+icon.getWidth();
        int[] offset = new int[2];
        Bitmap shadow = icon.extractAlpha(mBlurPaint, offset);
        Bitmap result = Bitmap.createBitmap(mIconSize, mIconSize, Config.ARGB_8888);
        mCanvas.setBitmap(result);

        // Draw ambient shadow
        mDrawPaint.setAlpha(AMBIENT_SHADOW_ALPHA);
        mCanvas.drawBitmap(shadow, offset[0], offset[1], mDrawPaint);

        // Draw key shadow
        mDrawPaint.setAlpha(KEY_SHADOW_ALPHA);
        mCanvas.drawBitmap(shadow, offset[0], offset[1] + KEY_SHADOW_DISTANCE * mIconSize, mDrawPaint);

        // Draw the icon
        mDrawPaint.setAlpha(255);
        mCanvas.drawBitmap(icon, 0, 0, mDrawPaint);

        mCanvas.setBitmap(null);
        return result;
    }



    public static ShadowGenerator getInstance(Context context) {

        synchronized (LOCK) {
            if (sShadowGenerator == null) {
                sShadowGenerator = new ShadowGenerator(context);
            }
        }
        return sShadowGenerator;
    }

}

-1

Nếu bạn muốn sử dụng imageView tùy chỉnh, tôi khuyên bạn nên sử dụng cái này

Chế độ xem trông hoàn hảo và không sử dụng bất kỳ hình ảnh chín đường dẫn nào

nhập mô tả hình ảnh ở đây

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.