2013-09-23 21 views
12

Sto provando a posizionare un ImageView in modo che la parte inferiore dell'immagine sia sempre fissata nella parte inferiore della vista, indipendentemente dalla ridotta altezza dell'immagine. Tuttavia, nessuno dei tipi di scala sembra adattarsi a quello che sto cercando di fare. CenterCrop è chiuso, ma non voglio che l'immagine sia centrata. Simile a come CSS gestirà il posizionamento assoluto.Android - ImageView bottomCrop anziché centerCrop

Il motivo è, ho bisogno di animare l'altezza del ImageView, ma farlo sembrare come se fosse "rivelando" la porzione superiore dell'immagine. Immagino che capire questo metodo per ritagliare l'immagine e animare l'altezza di ImageView sia il modo più semplice per farlo, ma se qualcuno sa meglio, mi piacerebbe essere indirizzato nella giusta direzione.

Qualsiasi aiuto apprezzato.

risposta

19

Ho terminato la sottoclasse di ImageView e ho creato un modo per abilitare un ridimensionamento dell'immagine di tipo 'BottomCrop'.

Ho assegnato l'immagine a un RectF della dimensione corretta calcolando la scala e l'altezza dell'immagine prevista in base all'altezza della vista.

public class BottomCropImage extends ImageView { 

public BottomCropImage(Context context) { 
    super(context); 
    setup(); 
} 

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

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

private void setup() { 
    setScaleType(ScaleType.MATRIX); 
} 

@Override 
protected boolean setFrame(int l, int t, int r, int b) { 
    Matrix matrix = getImageMatrix(); 

    float scale; 
    int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 
    int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 
    int drawableWidth = getDrawable().getIntrinsicWidth(); 
    int drawableHeight = getDrawable().getIntrinsicHeight(); 

    //Get the scale 
    if (drawableWidth * viewHeight > drawableHeight * viewWidth) { 
     scale = (float) viewHeight/(float) drawableHeight; 
    } else { 
     scale = (float) viewWidth/(float) drawableWidth; 
    } 

    //Define the rect to take image portion from 
    RectF drawableRect = new RectF(0, drawableHeight - (viewHeight/scale), drawableWidth, drawableHeight); 
    RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); 
    matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL); 


    setImageMatrix(matrix); 

    return super.setFrame(l, t, r, b); 
}   

} 
+0

Come convertirlo in TopCropImage? – Mani

+1

@Mani Ho finito per fare entrambe le cose, ho pensato che sarebbe stato utile! [Link Github] (https://github.com/Jpoliachik/BottomTopCropImage/blob/master/example/src/com/justinpoliachik/bottomtopcropimage/TopCropImage.java) – Jpoliachik

+0

L'ho fatto da solo, perché devo completarlo ieri stesso , grazie comunque, ho fatto lo stesso come hai fatto – Mani

-2

Hai provato lo Scaletype di Imageview FIT_END Questa è la migliore opzione disponibile per mostrare la fine di un'immagine.

+2

FIT_END non ritaglia l'immagine. Si adatta all'immagine nella cornice disponibile. Sembra che nessuno dei tipi di scala disponibili faccia ciò che sto cercando, ma ho bisogno di sottoclasse ImageView. – Jpoliachik

+0

Proprio così, FIT_END non ritaglia l'immagine. Ma questa è l'unica opzione disponibile per mostrare la fine dell'immagine. – prijupaul

12

Ho usato il codice @Jpoliachik e ha funzionato bene, ho fatto un paio di modifiche, perché a volte getWidth e getHeight stavano tornando 0-getMeasuredWidth e getMeasuredHeight risolto il problema.

@Override 
protected boolean setFrame(int l, int t, int r, int b) { 
    if (getDrawable() == null) 
     return super.setFrame(l, t, r, b); 

    Matrix matrix = getImageMatrix(); 

    float scale; 
    int viewWidth = getMeasuredWidth() - getPaddingLeft() - getPaddingRight(); 
    int viewHeight = getMeasuredHeight() - getPaddingTop() - getPaddingBottom(); 
    int drawableWidth = getDrawable().getIntrinsicWidth(); 
    int drawableHeight = getDrawable().getIntrinsicHeight(); 
    //Get the scale 
    if (drawableWidth * viewHeight > drawableHeight * viewWidth) { 
     scale = (float) viewHeight/(float) drawableHeight; 
    } else { 
     scale = (float) viewWidth/(float) drawableWidth; 
    } 

    //Define the rect to take image portion from 
    RectF drawableRect = new RectF(0, drawableHeight - (viewHeight/scale), drawableWidth, drawableHeight); 
    RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); 
    matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL); 

    setImageMatrix(matrix); 

    return super.setFrame(l, t, r, b); 
} 
+1

Questo risolve i problemi che ho avuto con il passaggio tra orizzontale e verticale, grazie. – Gabe

+1

Il codice 'Jpoliachik' soffre di un problema quando la tastiera virtuale ridimensiona il' ImageView' (quando l'allegata 'Activity' ha' android: windowSoftInputMode = "adjustResize" '). Il tuo codice risolve questo problema così buon lavoro! Thx –

30

Jpoliachik's risposta era abbastanza fresco per fare venire voglia di generalizzare per supportare sia superiore/inferiore e sinistra/destra, da un importo variabile. :) A questo punto è sufficiente chiamare il numero setOffset(0,0), il raccolto inferiore setOffset(0,1), il ritaglio a sinistra è anche setOffset(0,0) e il ritaglio destro setOffset(1,0). Se vuoi spostare la vista di una frazione dell'immagine in una dimensione, puoi chiamare ad es. setOffset(0, 0.25f) per spostarlo verso il basso del 25% dello spazio non visibile, mentre 0.5f lo centrerebbe. Saluti!

public class CropImageView extends ImageView { 
    float mWidthPercent = 0, mHeightPercent = 0; 

    public CropImageView(Context context) { 
     super(context); 
     setup(); 
    } 

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

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

    // How far right or down should we place the upper-left corner of the cropbox? [0, 1] 
    public void setOffset(float widthPercent, float heightPercent) { 
     mWidthPercent = widthPercent; 
     mHeightPercent = heightPercent; 
    } 

    private void setup() { 
     setScaleType(ScaleType.MATRIX); 
    } 

    @Override 
    protected boolean setFrame(int l, int t, int r, int b) { 
     Matrix matrix = getImageMatrix(); 

     float scale; 
     int viewWidth = getWidth() - getPaddingLeft() - getPaddingRight(); 
     int viewHeight = getHeight() - getPaddingTop() - getPaddingBottom(); 
     int drawableWidth = 0, drawableHeight = 0; 
     // Allow for setting the drawable later in code by guarding ourselves here. 
     if (getDrawable() != null) { 
      drawableWidth = getDrawable().getIntrinsicWidth(); 
      drawableHeight = getDrawable().getIntrinsicHeight(); 
     } 

     // Get the scale. 
     if (drawableWidth * viewHeight > drawableHeight * viewWidth) { 
      // Drawable is flatter than view. Scale it to fill the view height. 
      // A Top/Bottom crop here should be identical in this case. 
      scale = (float) viewHeight/(float) drawableHeight; 
     } else { 
      // Drawable is taller than view. Scale it to fill the view width. 
      // Left/Right crop here should be identical in this case. 
      scale = (float) viewWidth/(float) drawableWidth; 
     } 

     float viewToDrawableWidth = viewWidth/scale; 
     float viewToDrawableHeight = viewHeight/scale; 
     float xOffset = mWidthPercent * (drawableWidth - viewToDrawableWidth); 
     float yOffset = mHeightPercent * (drawableHeight - viewToDrawableHeight); 

     // Define the rect from which to take the image portion. 
     RectF drawableRect = new RectF(xOffset, yOffset, xOffset + viewToDrawableWidth, 
       yOffset + viewToDrawableHeight); 
     RectF viewRect = new RectF(0, 0, viewWidth, viewHeight); 
     matrix.setRectToRect(drawableRect, viewRect, Matrix.ScaleToFit.FILL); 

     setImageMatrix(matrix); 

     return super.setFrame(l, t, r, b); 
    } 
} 
+7

Sono stato modificato in modo che il codice di dimensionamento venisse chiamato dal metodo onSizeChanged() anziché da setFrame() perché non sarebbe stato chiamato dopo un ridimensionamento e l'immagine non sarebbe stata allineata correttamente. Sembra funzionare. Grazie –

+1

Come ha detto Carlos Fonseca, è meglio inserire il codice di ridimensionamento in onSizeChanged(), soprattutto se si utilizza questo CropImageView in un visualizzatore di pagine, o si avranno alcune immagini che non vengono visualizzate affatto –

Problemi correlati