2013-07-12 35 views
12

Tôi đang phát triển một Ứng dụng để vẽ các đường thẳng trên một loạt Hình ảnh. Để chọn những hình ảnh này, tôi có một nhóm radio và bất cứ khi nào người dùng nhấp vào nút radio, hình ảnh sẽ được tải với tất cả các bản vẽ của riêng nó.Làm thế nào để có được khi một ImageView được tải hoàn toàn trong Android

Trong listenner đài phát thanh của tôi, tôi có đoạn mã sau:

bitmap = BitmapUtils.decodeSampledBitmapFromResource(root + DefinesAndroid.CAMINHO_SHOPPINGS_SDCARD + nomeImagemAtual, size.x, size.y); 
mImage.setImageBitmap(bitmap); 

mImage.setDrawLines(true); 
mImage.setImageBitmap(loadBitmapFromView(mImage)); 

phương pháp decodeSampledBitmapFromResource tôi nhận được từ liên kết này trên các nhà phát triển Android (nó tải bitmap effitiently hơn) http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Và đây là phương pháp tôi gọi để có được Ảnh bitmap của Chế độ xem

public static Bitmap loadBitmapFromView(View v) { 
     Bitmap b = Bitmap.createBitmap(v.getLayoutParams().width, v.getLayoutParams().height, Bitmap.Config.ARGB_8888);     
     Canvas c = new Canvas(b); 
     v.layout(0, 0, v.getLayoutParams().width, v.getLayoutParams().height); 
     v.draw(c); 
     return b; 
} 

Tôi đang đặt hình ảnh Bitmap là mImage vì tôi đang sử dụng Im Thư viện ageViewTouch (cho phép phóng to thu nhỏ trên một ImageView) và nếu tôi không làm điều đó, tất cả bản vẽ canvas sẽ bị xóa với bất kỳ tương tác nào trên hình ảnh (như phóng to/thu nhỏ).

Các lỗi đăng nhập như sau

07-11 21:13:41.567: E/AndroidRuntime(20056): java.lang.IllegalArgumentException: width and height must be > 0 
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:638) 
07-11 21:13:41.567: E/AndroidRuntime(20056): at android.graphics.Bitmap.createBitmap(Bitmap.java:620) 

Tôi gần như chắc chắn rằng lỗi này xảy ra nguyên nhân bitmap hình ảnh không hoàn toàn nạp khi tôi gọi getBitmapFromView phương pháp.

Làm cách nào để biết thời điểm xem được tải hoàn toàn?

+0

uhm Tôi không nhận được nó, bạn có thể giải thích cho tôi một lần nữa trong mã của bạn? bạn đã đặt setImageBitmap lần đầu tiên. Tại sao bạn muốn đặt nó lần thứ hai và tải với và chiều cao từ xem? –

+0

lần đầu tiên tải ảnh sạch (không có bản vẽ). sau đó tôi vẽ các đường lên hình ảnh bằng cách gọi setDrawLines .. một khi các bản vẽ được vẽ trên Canvas, tôi phải tạo một hình ảnh duy nhất của hình ảnh + bản vẽ .. vì vậy tôi gọi, lần thứ hai, imageBitmap, nhưng lần này , Tôi phải lấy bitmap từ khung nhìn (vì khung nhìn có các hình vẽ) .. theo cách này tôi đặt chúng lại với nhau –

+0

Dường như http://stackoverflow.com/questions/8831642/how-to-draw này -lines-over-imageview-on-android sẽ có nhiều hơn những gì bạn muốn. –

Trả lời

21

Gọi loadBitmapFromView theo cách như vậy:

mImage.post(new Runnable() { 
    @Override 
    public void run() { 
     loadBitmapFromView(mImage); 
    } 
}); 

Runnable cung cấp cho post() phương pháp sẽ được thực hiện sau khi xem đo và layouting, vì vậy getWidth()getHeight() sẽ trở lại chiều rộng thực tế và chiều cao.

Bạn có thể làm gì khác, đang đo View theo cách thủ công, bằng cách gọi measure và sau đó lấy kết quả từ getMeasuredWidth()getMeasuredHeight(). Nhưng tôi không khuyên bạn nên làm theo cách này.

+0

Nó cuối cùng cũng hoạt động !!! Tôi chỉ cần setImageBitmap bên trong phương thức run() và mọi thứ đều ổn! Tôi đánh giá cao nó rất nhiều! Tôi sẽ bỏ phiếu 10 lần trong câu trả lời của bạn nếu tôi có thể! :) –

+0

Đồng ý với Felipe ... Tôi đã dành một thời gian dài tìm kiếm để thử và tìm ra một phương pháp tương tự. Cảm ơn bạn! – RiddlerDev

+1

@RiddlerDev kiểm tra giải pháp khác (được đăng bởi tôi) với 'OnPreDrawListener'. –

8

Có một cách khác đáng tin cậy hơn để thực hiện điều đó bằng cách sử dụng ViewTreeObserver.OnPreDrawListener. Và đây là một ví dụ:

mImage.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener(){ 

    @Override 
    public boolean onPreDraw() { 
     try { 
      loadBitmapFromView(mImage);    
      return true; //note, that "true" is important, since you don't want drawing pass to be canceled 
     } finally { 
      mImage.getViewTreeObserver().removeOnPreDrawListener(this); //we don't need any further notifications 
     } 
    } 
}); 

Sử dụng OnPreDrawListenerđảm bảo rằng View được đo và layouted, trong khi View#post(Runnable) chỉ thực hiện Runnable của bạn khi tất cả xem đã hầu đo và layouted.

+0

Đây là giải pháp duy nhất hoạt động mà không bị trễ. – Vyacheslav

1

Dưới đây là lớp NotifyImageView hoạt động kết hợp phương thức của Dmitry trên và thêm mã để thông báo sau khi ImageView thực sự có thể sử dụng được.

Tôi hy vọng bạn thấy nó hữu ích.

'

public interface NotifyImageHolder { 
    public void notifyImageChanged(final NotifyImageView thePosterImage, final int width, final int height); 
} 

import android.content.Context; 
import android.graphics.Bitmap; 
import android.graphics.drawable.Drawable; 
import android.util.AttributeSet; 
import android.view.ViewTreeObserver; 
import android.widget.ImageView; 

public class NotifyImageView extends ImageView { 
    private boolean mImageChanged; 
    private NotifyImageHolder mHolder; 
    private boolean mImageFinished; 

    public NotifyImageView(Context context) { 
     super(context); 
     init(); 
    } 

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

    public NotifyImageView(Context context, AttributeSet attrs, int defStyleAttr) { 
     super(context, attrs, defStyleAttr); 
     init(); 
    } 

    protected void init() { 
     mImageChanged = false; 
     mImageFinished = false; 
     mHolder = null; 
     monitorPreDraw(); 
    } 

    // so we can tell when the image finishes loading.. 
    protected void monitorPreDraw() { 
     final NotifyImageView thePosterImage = this; 
     getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { 

      @Override 
      public boolean onPreDraw() { 
       try { 
        return true; //note, that "true" is important, since you don't want drawing pass to be canceled 
       } finally { 
        getViewTreeObserver().removeOnPreDrawListener(this); // we don't need any further notifications 
        thePosterImage.buildDrawingCache(); 
        mImageFinished = true; 
       } 
      } 
     }); 
    } 

    public void setNotifyImageHolder(NotifyImageHolder holder) { 
     this.mHolder = holder; 
    } 

    public boolean isImageChanged() { 
     return mImageChanged; 
    } 

    public boolean isImageFinished() { 
     return mImageFinished; 
    } 

    public void notifyOff() { 
     mHolder = null; 
    } 

    // the change notify happens here.. 
    @Override 
    public void setImageDrawable(Drawable noPosterImage) { 
     super.setImageDrawable(noPosterImage); 
     if (mHolder != null && mImageFinished) { 
      mImageFinished = false; // we send a single change-notification only 
      final NotifyImageView theNotifyImageView = this; 

      theNotifyImageView.post(new Runnable() { 
       @Override 
       public void run() { 
        if (mHolder != null) { 
         int width = getMeasuredWidth(); 
         int height = getMeasuredHeight(); 
         mImageChanged = true; 
         mHolder.notifyImageChanged(theNotifyImageView, width, height); 
        } 
       } 
      }); 

     } 
    } 

} 

'

+0

Bạn không thực sự cần phải sử dụng quan sát cây xem ở đây. Vì bạn có quyền truy cập đầy đủ vào việc triển khai khung nhìn, bạn chỉ có thể nhận được kích thước của bạn trong phương thức 'onDraw()'. –