2013-07-12 6 views
12

Ich entwickle eine App, die Linien über eine Reihe von Bildern zeichnet. Um diese Bilder auszuwählen, habe ich eine Radiogruppe, und wenn der Benutzer in einen Radioknopf klickt, wird das Bild mit allen seinen eigenen Zeichnungen geladen.Wie bekomme ich, wenn ein ImageView vollständig in Android geladen wird

In meinem Radio listenner Ich habe den folgenden Code:

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

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

die decodeSampledBitmapFromResource Methode, die ich von diesem Link auf Android-Entwickler bekommen (es lädt Bitmaps mehr effitiently) http://developer.android.com/training/displaying-bitmaps/load-bitmap.html

Und hier ist die Methode, die ich nennen eine Bitmap einer Ansicht

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; 
} 

ich gründe das Bild Bitmap von mImage zu bekommen, weil ich bin mit Im ageViewTouch-Bibliothek (ermöglicht Pinch-Zooming über ein ImageView) und wenn ich es nicht mache, wird die gesamte Canvas-Zeichnung gelöscht mit jeder Interaktion über das Bild (wie Zoomen in/out).

Das Fehlerprotokoll ist das folgende

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) 

ich fast sicher bin, dass dieser Fehler auftreten Ursache das Bitmap-Bild wird nicht vollständig geladen, wenn ich getBitmapFromView Methode aufrufen.

Wie kann ich wissen, wann die Ansicht vollständig geladen ist?

+0

uhm ich nicht bekommen, es würde sie mich wieder in Ihrem Code erklären? Sie haben ImageBitmap das erste Mal gesetzt. Warum möchtest du es zum zweiten Mal einstellen und laden mit und Höhe aus Sicht? –

+0

das erste Mal ist das Bild sauber zu laden (ohne Zeichnungen). dann zeichne ich die Linien über die Bilder, indem ich setDrawLines aufruft. Sobald die Zeichnungen auf Canvas gezeichnet sind, muss ich ein einzigartiges Bild des Bildes und der Zeichnungen erstellen. Also rufe ich zum zweiten Mal die imageBitmap auf, diesmal aber Ich muss die Bitmap aus der Ansicht holen (weil die Ansicht die Zeichnungen hat). Auf diese Weise stelle ich sie zusammen –

+0

Es scheint, dass dies http://stackoverflow.com/questions/8831642/how-to-draw -lines-over-imageview-on-android wäre mehr von dem, was Sie wollen. –

Antwort

21

loadBitmapFromView Anruf in einer Weise:

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

Runnable zu post() Verfahren bereitgestellt wird nach Ansicht Mess- und Layouten ausgeführt werden, so getWidth() und getHeight() werden tatsächliche Breite und Höhe zurückzukehren.

Was können Sie tun, ist die Messung View manuell, durch measure Aufruf, und dann resultieren aus getMeasuredWidth() und getMeasuredHeight() nehmen. Aber ich empfehle diesen Weg nicht.

+0

Es funktioniert endlich !!! Ich muss nur ImageBitmap innerhalb der run() -Methode setzen und alles ging gut! Ich schätze es sehr! Ich würde 10 Mal in Ihrer Antwort abstimmen, wenn ich könnte! :) –

+0

Einverstanden mit Felipe ... Ich habe lange gesucht, um eine ähnliche Methode zu finden. Vielen Dank! – RiddlerDev

+1

@RiddlerDev überprüfen Sie eine andere Lösung (von mir gepostet) mit 'OnPreDrawListener'. –

8

Es gibt tatsächlich eine andere, zuverlässigere Möglichkeit, das zu tun, indem Sie ViewTreeObserver.OnPreDrawListener verwenden. Und hier ist ein Beispiel:

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 
     } 
    } 
}); 

Mit OnPreDrawListenerGarantien dass View gemessen wurde und layoutet, während View#post(Runnable) nur Ihre Runnable ausführt, wenn alle Ansichten sind bereits höchstwahrscheinlich gemessen und layoutet.

+0

Dies ist die einzige Lösung, die ohne Verzögerungen funktioniert. – Vyacheslav

1

Unten ist eine funktionierende NotifyImageView-Klasse, die die Dmitry-Methode über enthält und Code hinzufügt, um erst dann zu benachrichtigen, wenn die ImageView wirklich verwendbar ist.

Ich hoffe, Sie finden es nützlich.

`

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

Sie müssen hier nicht wirklich den View Tree Observer verwenden. Da Sie vollen Zugriff auf die View-Implementierung haben, können Sie einfach Ihre Größe in der 'onDraw()' Methode erhalten. –

Verwandte Themen