requestFeature () należy wywołać przed dodaniem treści


135

Próbuję zaimplementować niestandardowy pasek tytułu:

Oto moja klasa pomocnicza:

import android.app.Activity;
import android.view.Window;

public class UIHelper {
    public static void setupTitleBar(Activity c) {
        final boolean customTitleSupported = c.requestWindowFeature(Window.FEATURE_CUSTOM_TITLE);

        c.setContentView(R.layout.main);

        if (customTitleSupported) {
            c.getWindow().setFeatureInt(Window.FEATURE_CUSTOM_TITLE, R.layout.titlebar);
        }
    }
}

Oto miejsce, w którym nazywam to w onCreate ():

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setupUI();
}

private void setupUI(){
     setContentView(R.layout.main);
     UIHelper.setupTitleBar(this);
}

Ale pojawia się błąd:

requestFeature() must be called before adding content

Odpowiedzi:


331

Po prostu zrób to, co mówi komunikat o błędzie.

Nie dzwoń setContentView()wcześniej requestFeature().

Uwaga:

Jak wspomniano w komentarzach, zarówno w przypadku biblioteki, jak ActionBarSherlocki AppCompatbiblioteki, należy requestFeature()wcześniej zadzwonićsuper.onCreate()


60
cholera, to jest klasyczna odpowiedź.
Osoba

60
W przypadku ActionBarSherlock konieczne jest również wywołanie requestFeature()przed super.onCreate(). Źródła
Saran,

1
Co zrobić, jeśli chcesz pokazać jeden układ bez paska tytułu, a następnie pokazać jeden z paskiem tytułu? Będziesz musiał użyć, requestWindowFeature(Window.FEATURE_NO_TITLE)aby go ukryć, a następnie setContentView()dla pierwszego układu, a następnie requestWindowFeature(Window.FEATURE_CUSTOM_TITLE)ponownie wyświetlić pasek tytułu. To będzie po setContentView()raz drugi.
msbg

35
To ten sam przypadek w AppCompat, jak powiedział @Saran. Musisz zadzwonić requestFeaturewcześniejsuper.onCreate()
Jaison Brooks

7
Ta odpowiedź niewiele pomaga ... ale co ja wiem
Ojonugwa Jude Ochalifu

23

Wiem, że ma ponad rok, ale telefon requestFeature()nigdy nie rozwiązał mojego problemu. W rzeczywistości wcale tego nie nazywam.

Przypuszczam, że był to problem z zawyżeniem widoku. Pomimo wszystkich moich poszukiwań, nigdy nie znalazłem odpowiedniego rozwiązania, dopóki nie bawiłem się różnymi metodami powiększania widoku.

AlertDialog.Builder to łatwe rozwiązanie, ale wymaga dużo pracy, jeśli używasz onPrepareDialog()do aktualizacji tego widoku.

Inną alternatywą jest wykorzystanie AsyncTask do dialogów.

Ostateczne rozwiązanie, które zastosowałem, jest poniżej:

public class CustomDialog extends AlertDialog {

   private View content;

   public CustomDialog(Context context) {
       super(context);

       LayoutInflater li = LayoutInflater.from(context);
       content = li.inflate(R.layout.custom_view, null);

       setUpAdditionalStuff(); // do more view cleanup
       setView(content);           
   }

   private void setUpAdditionalStuff() {
       // ...
   }

   // Call ((CustomDialog) dialog).prepare() in the onPrepareDialog() method  
   public void prepare() {
       setTitle(R.string.custom_title);
       setIcon( getIcon() );
       // ...
   }
}

* Kilka dodatkowych uwag:

  1. Nie polegaj na ukrywaniu tytułu. Często jest puste miejsce, mimo że tytuł nie jest ustawiony.
  2. Nie próbuj tworzyć własnego widoku ze stopką nagłówka i środkowym widokiem. Nagłówek, jak wspomniano powyżej, może nie być całkowicie ukryty pomimo żądania FEATURE_NO_TITLE.
  3. Nie stylizuj widoku treści za pomocą atrybutów kolorów lub rozmiaru tekstu. Niech okno dialogowe sobie z tym poradzi, w przeciwnym razie ryzykujesz umieszczenie czarnego tekstu na ciemnoniebieskim oknie dialogowym, ponieważ dostawca odwrócił kolory.

Początkowo zamieściłem setTitle () i setIcon () w metodzie onCreate (), ale edycja przeniosła ją do metody ready (), która jest wywoływana podczas metody onPrepareDialog ().
Cookster

2
Dzięki za udostępnienie. Myślę, że następujący wiersz content = inflater.inflate(R.layout.custom_view, null);prawdopodobnie powinien content = li.inflate(R.layout.custom_view, null);. Więc inflatermusi zostać zastąpiony przez li.
aLearner

14

Rozszerzałem DialogFragment i powyższa odpowiedź nie działa. Musiałem użyć getDialog (), aby usunąć tytuł:

getDialog().getWindow().requestFeature(Window.FEATURE_NO_TITLE);

@ojonugwaochalifu to było jakiś czas temu, więc nie pamiętam dokładnie, ale jestem pewien, że trzeba to zrobić przed metodą setcontentView ()
Illegal Argument

1
dla każdego, kto boryka się z tym samym problemem: dodałem ten kod w onViewCreated ();
7geeky

2

Czy błąd nie mówi dokładnie, co jest nie tak? Dzwonisz requestWindowFeaturei setFeatureIntpo tym, jak dzwonisz setContentView.

Swoją drogą, dlaczego dzwonisz setContentViewdwa razy?


2

W przypadku zestawu SDK w wersji 23 i nowszych ten sam RuntimeException jest generowany, jeśli używasz AppCompatActivity do rozszerzenia aktywności. Nie stanie się tak, jeśli Twoja aktywność wywodzi się bezpośrednio z Aktywności.

Jest to znany problem w Google, o którym mowa w https://code.google.com/p/android/issues/detail?id=186440

Rozwiązaniem przewidzianym w tym celu jest użycie metody supportRequestWindowFeature () zamiast requestFeature ().

Proszę zagłosuj za, jeśli to rozwiąże twój problem.


1

Zmień wersję kompilacji SDK , wersja docelowa SDK do wersji kompilacji Narzędzia do 24.0.0 w build.gradle jeśli u obliczu problemu w Zgłoszenie błędu


0

W moim przypadku pokazałem DialogFragmentw Activity. W tym fragmencie okna dialogowego napisałem jak w DialogFragment usuń czarne obramowanie :

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setStyle(STYLE_NO_FRAME, 0)
}

override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
    super.onCreateDialog(savedInstanceState)

    val dialog = Dialog(context!!, R.style.ErrorDialogTheme)
    val inflater = LayoutInflater.from(context)
    val view = inflater.inflate(R.layout.fragment_error_dialog, null, false)
    dialog.setTitle(null)
    dialog.setCancelable(true)
    dialog.setContentView(view)
    return dialog
}

Albo usunąć setStyle(STYLE_NO_FRAME, 0)się onCreate()lub chande / usuń onCreateDialog. Ponieważ ustawienia okna dialogowego uległy zmianie po jego utworzeniu.


0

Miałem ten problem z Dialogami opartymi na rozszerzonym DialogFragment, który działał dobrze na urządzeniach z API 26, ale zawiódł z API 23. Powyższe strategie nie działały, ale rozwiązałem problem, usuwając metodę onCreateView (która została dodana przez bardziej ostatni szablon Android Studio) z DialogFragment i tworzenie okna dialogowego w onCreateDialog.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.