2015-01-28 12 views
1

저는 ImageView, 전체 너비 및 너비 : 높이 = 3 : 1을 가지고 있습니다. 1200 x 400이라고합시다. ImageView에 두 개의 Drawable 두 개를 표시하려고합니다. 두 개는 모두 런타임에만 알려져 있습니다. 드로어 블 중 하나는 "center-crop"에 따라 ImageView에 배치해야합니다. 드로어 블이 width : height> 3 인 경우, 너비가 정확히 맞고 위쪽과 아래쪽이 잘리는 것을 의미합니다. 다른 쪽은 가운데 맞추기 및 크기 조절해야합니다. 맞춤 요인으로LayerDrawable :이 작업을보다 효율적으로 수행 할 수 있습니까?

이 작업을 수행하는 코드가 있지만 불필요하게 복잡합니다. 나는 LayerDrawable에서 새 Bitmap을 만들고 그 다음에 BitmapDrawable을 만들었을 때 LayerDrawable에 이미 경계를 설정했지만 BitmapDrawable에 원하는 경계를 다시 설정할 때만 원하는대로 작동하도록 할 수있었습니다. 그러나 그 경계는 다음과 같습니다. 여분의 단계를 수행하지 않으면 무시됩니다. 나는 .setImageDrawable()에 그대로 사용할 수있는 그런 방식으로 LayerDrawable을 생성하는 것을 선호하지만, 어떻게해야할지 모르겠다. 시도해도 Android가하는 일은 나에게 의미가 없습니다. 내가 도대체 ​​뭘 잘못하고있는 겁니까?

이 내가 만드는 방법입니다 LayerDrawable

double divide(int k, int n) { 
    return ((double)k)/n; 
} 
int verticalPaddingForHorizontalFit(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight){ 
    // you want to draw a drawable into a view, with an exact match in the width. Then either [1] or [2] 
    // [1] the view is taller than the drawable (i.e., height/width bigger for the view) 
    //  --> method result is positive, 
    //  and gives the amount of padding top and bottom 
    // [2] the drawable is taller 
    //  --> method result is negative, 
    //   and gives (minus) the amount that needs to be clipped from top and bottom 
    // such that the drawable is vertically centered 
    double viewAspect  = divide(viewHeight,  viewWidth ); 
    double drawableAspect = divide(drawableHeight, drawableWidth); 
    return (int)Math.round(0.5 * viewWidth * (viewAspect - drawableAspect)); 
} 
int[] paddingWhenCenteredAt(int viewWidth, int viewHeight, int drawableWidth, int drawableHeight, double drawableScale, int centerX, int centerY){ 
    // scale the drawable with drawableScale, and put it into the view 
    // such that the center of the drawable has coordinates (centerX, centerY) 
    // return the padding needed as array of left, top, right, bottom, in that order 
    // negative values indicating clipping instead of padding 
    double w = drawableScale * drawableWidth; 
    double h = drawableScale * drawableHeight; 
    double left = centerX - 0.5*w; 
    double right = viewWidth - (centerX + 0.5*w); 
    double top = centerY - 0.5*h; 
    double bottom = viewHeight - (centerY + 0.5*h); 
    return new int[]{(int)Math.round(left), (int)Math.round(top), (int)Math.round(right), (int)Math.round(bottom)}; 
} 
LayerDrawable makeLayerDrawable(Resources r, int outputWidth, int outputHeight, Bitmap bm1, Bitmap bm2){ 
    Drawable[] layers = new Drawable[2]; 
    BitmapDrawable bmd1 = new BitmapDrawable(r, bm1); 
    int width1 = bmd1.getIntrinsicWidth(); 
    int height1 = bmd1.getIntrinsicHeight(); 
    layers[0] = bmd1; 
    BitmapDrawable bmd2 = new BitmapDrawable(r, bm2); 
    int width2 = bmd2.getIntrinsicWidth(); 
    int height2 = bmd2.getIntrinsicHeight(); 
    layers[1] = bmd2; 
    LayerDrawable result = new LayerDrawable(layers); 
    int vPad = verticalPaddingForHorizontalFit(outputWidth, outputHeight, width1, height1); 
    result.setLayerInset(0, 0, vPad, 0, vPad); 
    int[] ltrb = paddingWhenCenteredAt(outputWidth, outputHeight, width2, height2, 0.5, outputWidth/2, outputHeight/2); 
    result.setLayerInset(1, ltrb[0], ltrb[1], ltrb[2], ltrb[3]); 
    result.setBounds(0, 0, outputWidth, outputHeight); 
    return result; 
} 

(I는 비트 맵 BM1 2400 x 1200 픽셀 비트 맵 BM2 800 x 300 픽셀로 테스트했습니다.)

지금, 난 그냥 LayerDrawable 것을 사용하는 경우 , 그래서

myImageView.setImageDrawable(layd); 

처럼 ImageView은 (높이 변경.) 원하는 크기가되지 않습니다 내가다시 레이아웃을 설정하는 경우, 그걸 막을 수는 있지만 드로어 블이 올바르게 표시되지 않습니다. 대신, 나는 이것을한다

LayerDrawable layd = makeLayerDrawable(r, outputWidth, outputHeight, bm1, bm2); 
    Bitmap b = Bitmap.createBitmap(outputWidth, outputHeight, Bitmap.Config.ARGB_8888); 
    Canvas canvas = new Canvas(b); 
    layd.draw(canvas); 
    BitmapDrawable result = new BitmapDrawable(getResources(), b); 
    result.setBounds(0, 0, outputWidth, outputHeight); 
    myImageView.setImageDrawable(result); 

그것은 작동한다.

Here는 github에

난 그 하드가 보인다 아닌 자신의 Drawable 클래스를 작성 고려할 것이라고
+0

ImageView는 레이아웃의 일부로 이미지 드로어 블에 setBounds()를 호출합니다. 경계를 설정하려고 수동으로 호출하면 효과가 없습니다. BitmapDrawable 레이어에 [gravity] (http://developer.android.com/reference/android/graphics/drawable/BitmapDrawable.html#attr_android:gravity)를 설정하는 것을 고려해야합니다. – alanv

+0

@alanv. 1) 중력이 내 목적에 충분히 융통성이 없다고 생각합니다. 드로어 블 중 하나는 가운데도 구석에도 없습니다. 2) (screenWidth x screenWidth/3) 뷰의 픽셀 크기를 원하는 것을 알고있다 - 나보다 똑똑해 지려고 시도하고있는 ImageView 알려주고 setBounds() 호출하지 않는 방법은 무엇입니까? – mathheadinclouds

+0

ImageView의 기본 측정 및 레이아웃을 재정의해야합니다. 아래의 대답은 자신 만의 Drawable을 작성하는 것이 가장 좋은 방법이라고 제안하지만 LayerDrawable을 하위 클래스로 분류하는 것이 더 좋을 수도 있고 onBoundsChange() 메서드를 재정 의하여 개별 레이어에서 고유 한 setBounds()를 호출하는 것이 좋습니다. – alanv

답변

0

에 전체 코드입니다. Drawable에서 확장하고 draw()을 오버라이드하면 필요한 가로 세로 비율로 레이어 (쌓아 올린) 비트 맵으로 그릴 때와 똑같은 계산을 할 수 있습니다. Canvas.drawBitmap()가 문제를 해결하는 것처럼 보입니다.