2011-10-08 11 views
10

La maggior parte degli esempi là fuori specifica esattamente la larghezza e l'altezza della finestra popup. Voglio che siano wrap_content - dal momento che il contenuto è dinamicamente determinato, così nel costruttore ho impostato -2 sia per la larghezza e l'altezza e lo dimostrano tramite showAsDropDown (Vedi ancoraggio)PopupWindow fuori schermo quando la dimensione non è specificata

In questo modo, il popup viene sempre disegnata sotto la vista di ancoraggio, il che significa che può essere disegnato fuori dallo schermo. Il seguente frammento illustra il problema. Prova a fare clic sull'ultima TextView e non vedrai nessuna finestra popup, poiché è mostrata al di fuori dei limiti di Windows. Perché non funziona? Osservo che specificare la dimensione in modo esplicito (ad esempio 200, 100) non attiva il problema. Provate voi stessi

package com.zybnet.example.popupdemo; 

import android.app.Activity; 
import android.graphics.Color; 
import android.os.Bundle; 
import android.view.View; 
import android.view.View.OnClickListener; 
import android.widget.LinearLayout; 
import android.widget.PopupWindow; 
import android.widget.TextView; 

public class PopupDemoActivity extends Activity implements OnClickListener { 
    private PopupWindow popup; 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     // -2 means WRAP_CONTENT THIS TRIGGERS THE PROBLEM 
     popup = new PopupWindow(getPopupContent(), -2, -2); 
     // When you specify the dimensions everything goes fine 
     //popup = new PopupWindow(getPopupContent(), 200, 100); 

     LinearLayout layout = new LinearLayout(this); 
     layout.setOrientation(LinearLayout.VERTICAL); 

     // FILL_PARENT and same layout weight for all children 
     LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(-1, -1, 1); 
     for (int i = 0; i < 10; i++) { 
      TextView tv = new TextView(this); 
      tv.setText("Click to show popup"); 
      tv.setOnClickListener(this); 
      layout.addView(tv, params); 
     } 
     setContentView(layout); 
    } 

    @Override 
    public void onClick(View view) { 
     popup.dismiss(); 
     popup.showAsDropDown(view); 
    } 

    private View getPopupContent() { 
     TextView popupContent = new TextView(this); 
     popupContent.setText("Some text here"); 
     popupContent.setTextColor(Color.parseColor("#5000ae")); 
     popupContent.setBackgroundColor(Color.parseColor("#ff00ff")); 
     popupContent.setPadding(10, 20, 20, 10); 
     return popupContent; 
    } 
} 

risposta

16

sto iniziando a dubitare che, nel contesto di una PopupWindow che -2, -2 significa in realtà WRAP_CONTENT piuttosto penso che il suo solo interpretandolo come width = -2 height = -2

Questo è dal source Android

public PopupWindow(View contentView, int width, int height, boolean focusable) { 
    if (contentView != null) { 
     mContext = contentView.getContext(); 
     mWindowManager = (WindowManager) mContext.getSystemService(Context.WINDOW_SERVICE); 
    } 
    setContentView(contentView); 
    setWidth(width); 
    setHeight(height); 
    setFocusable(focusable); 
} 

dove setWidth(int width) è solo un semplice mWidth = width; Penso che quello che state cercando invece è il metodo setWindowLayoutMode (int widthSpec, int heightSpec). È qui che si dovrebbe passare nel WRAP_CONTENT

Se tutto il resto fallisce, misurare la larghezza e l'altezza del TextView e quindi utilizzare setWidth e setHeight come previsto.

Edit:

appena provato per me stesso e ha aggiunto questa riga di codice per farlo funzionare

// -2 means WRAP_CONTENT THIS TRIGGERS THE PROBLEM 
    popup = new PopupWindow(getPopupContent(), 200, 100); 
    popup.setWindowLayoutMode(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
    // When you specify the dimensions everything goes fine 
    //popup = new PopupWindow(getPopupContent(), 200, 100); 

    LinearLayout layout = new LinearLayout(this); 
    layout.setOrientation(LinearLayout.VERTICAL); 

ho lasciato i commenti originali in là in modo da poter vedere di persona dove tutto dovrei andare.

Edit 2: Va bene, così ho preso il codice che avete inviato e testuale provato sul mio dispositivo, e avevi ragione, non ha funzionato perché quando Android è determinare quali viste di layout per metterla in , dipende dalla larghezza e dall'altezza che hai fornito. Ciò significa che dal momento che stai usando 0 e 0 come larghezza e altezza, Android arriverà e dirà, "Guarda, la casella è solo una casella 0 per 0, quindi posso visualizzarla come popup sotto il contenuto." Questo non è ciò che si desidera però! Il fatto è che tu sai che la scatola sarà più grande di così, quindi iniziamo a inserire numeri diversi e a vedere i risultati che ne derivano.

popup = new PopupWindow(getPopupContent(), 1, 1); 

Ora quando vado a fare clic sulla casella in basso, si noti che salta sopra. (Vedi screenshot) Questo perché Android CONOSCE che la larghezza e l'altezza sono 1 (come ho impostato nel costruttore) e che lo spazio disponibile sullo schermo sotto la voce dell'elenco è 0. Bene, se non c'è abbastanza spazio per visualizzarlo lì, allora deve sopra allora!

enter image description here

Ma aspettate! Cosa succede se nel mio esempio attuale la stringa aggiunge più contenuti ogni volta? Bene, questo è dove le cose si fanno interessanti. Vedete, nel mio prossimo screenshot che il popup, anche se dovrebbe essere visualizzato poiché è lungo 6 righe ora, è piuttosto visualizzato in basso! Oh merda, giusto!Questo perché sta misurando con lo 1 1 che ho usato nel costruttore. Bene, quali sono alcune soluzioni a questo allora?

enter image description here

soluzione one: Il mio modo preferito sarebbe quello di prendere una supposizione a quello che l'altezza media massima del TextView sarebbe e poi semplicemente gettare in un unico genericamente gran numero.

popup = new PopupWindow(getPopupContent(), 300, 300); //just guessing it won't get bigger than that 

Soluzione 2: questo è più corretto, ma si sta sacrificando un po 'di velocità per farlo. Utilizzando la classe Paint per misurare quale sarà la dimensione del contenuto del testo e passarla nello setWidth() e setHeight() prima di visualizzare il popup. Sono andato avanti e costruito un quasi soluzione completa, ma non mi misuro in imbottitura e roba (vedi il commento)

private int maxWidth; 
private int maxHeight; 
private Paint p = new Paint(); 
private Rect bounds = new Rect(); 
private View getPopupContent() { 
    maxWidth = 0; 
    maxHeight = 0; 
    TextView popupContent = new TextView(this); 
    popupContent.setText(popupText += "\n" + DEMO); 
    popupContent.setTextColor(Color.parseColor("#5000ae")); 
    popupContent.setBackgroundColor(Color.parseColor("#ff00ff")); 
    popupContent.setPadding(10, 20, 20, 10); 
    //the measure can only work line by line so I split it up by line 
    String[] temp = popupText.split("\n"); 
    for (String s : temp){ 
     //measure each line of string and get its width and height 
     p.getTextBounds(s, 0, s.length(), bounds); 

     //keep a running total of the longest width 
     maxWidth = (bounds.width() > maxWidth) ? bounds.width() : maxWidth; 
     //add up each of the heights 
     maxHeight += bounds.height(); 
    } 

    //also take in account the padding too... if you REALLY want it to be completely robust 
    //probably adding another 20 or 30 to the maxHeight should be good 
    return popupContent; 
} 

E poi in onClick() ho aggiunto queste due righe

popup.setHeight(maxHeight); 
    popup.setWidth(maxWidth); 
+0

ho letto le fonti troppo, e sembra più un a bug ndroid, poiché la dimensione è corretta, ma il posizionamento è sbagliato. Puoi testarlo da solo, dal momento che ho fornito una demo. Ora sto sperimentando con PopupWindow.showAtLocation() – Raffaele

+0

Proprio come sospettavo che avessi bisogno di aggiungere in 'setWindowLayoutMode' ho modificato la mia risposta e aggiunto nel codice esatto di lavoro che ti serve. L'ho provato sul mio dispositivo Android e tutto! :) – Bob

+0

Cosa succede se la prossima volta che invochi il popup cambia la visualizzazione del contenuto? Ecco perché ho bisogno di WRAP_CONTENT – Raffaele

1

ho risolto questo problema chiamando measure() metodo in una visualizzazione di contenuti popup:

View content = getPopupContent(); 

content.measure(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT); 
int measuredHeight = content.getMeasuredHeight(); 

popup = new PopupWindow(content, ViewGroup.LayoutParams.WRAP_CONTENT, measuredHeight); 
Problemi correlati