11

Próbuję uzyskać fragment, który na tablecie będzie wyświetlany jako DialogFragment, a na smartfonie będzie wyświetlany jako zwykły fragment. Mam świadomość, że istnieje już similar post, ale nie jestem w stanie wykonać tej pracy - zastosuj styl do fragmentacji.Fragment systemu Android jest wyświetlany jako fragment okna dialogowego lub zwykły fragment.

Aby pokazać rzeczy, z góry na dół, MainActivity.java:

public class MainActivity extends ActionBarActivity { 

    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.activity_main); 
    } 

    @Override 
    public boolean onCreateOptionsMenu(Menu menu) { 
     getMenuInflater().inflate(R.menu.main, menu); 
     return true; 
    } 

    @Override 
    public boolean onOptionsItemSelected(MenuItem item) { 
     if (item.getItemId() == R.id.action_next) { 
      decideToNext(); 
      return true; 
     } 
     return super.onOptionsItemSelected(item); 
    } 

    private void decideToNext() { 
     String device = getString(R.string.device); 
     if ("normal".equalsIgnoreCase(device)) { 
      Intent intent = new Intent(this, DetailedActivity.class); 
      startActivity(intent); 
     } else if ("large".equalsIgnoreCase(device)) { 
      Log.d("SOME_TAG", "Yes, I am seeing this line on tablet only"); 
      DetailedFragment fragment = DetailedFragment.newInstance(); 
      getSupportFragmentManager().beginTransaction().add(fragment, "MAGIC_TAG").commit(); 
     } 
    } 

} 

DetailedActivity ma nic:

public class DetailedActivity extends ActionBarActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.detailed_activity); 
    } 
} 

jej układ:

<fragment xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/root_container" 
    android:name="com.myapps.sampleandroid.DetailedFragment" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

i interesujący DetailedFragment:

public class DetailedFragment extends Fragment { 

    public static DetailedFragment newInstance() { 
     return new DetailedFragment(); 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     Context contextThemeWrapper = new ContextThemeWrapper(getActivity(), R.style.MyDialogTheme); 
     LayoutInflater localInflater = inflater.cloneInContext(contextThemeWrapper); 
     return localInflater.inflate(R.layout.detailed_fragment, container, false); 
    } 
} 

... a jej układ:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <TextView 
     android:id="@+id/textView1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Regular Text" /> 

    <TextView 
     android:id="@+id/textView2" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Large Text" 
     android:textAppearance="?android:attr/textAppearanceLarge" /> 

    <Button 
     android:id="@+id/button1" 
     android:layout_width="wrap_content" 
     android:layout_height="wrap_content" 
     android:text="Button Dummy" /> 

</LinearLayout> 

W onCreateView Próbowałem ustawić niestandardową stylizację, ale nie wydają się działać na tablecie.

Styling

res/wartości/styles.xml zawiera:

<resources> 

    <style name="AppTheme" parent="@style/Theme.AppCompat.Light.DarkActionBar"> 
    </style> 

    <style name="MyDialogTheme" /> 

</resources> 

podczas RES/Wartości duży/styles.xml:

<resources> 
    <!-- Is there anything I should add here? --> 
    <style name="MyDialogTheme" parent="@android:style/Theme.Dialog"/> 
</resources> 

Mam zagnieżdżona MyDialogTheme od Theme.Dialog, ale to nie pomaga.

Na smartfonie, gdy dotknięcie „Next” menu bar działanie widzę szczegółową aktywność (snapshot z SG2): snapshot from an SG2

podczas gwintowania na tej samej pozycji menu „Next” z tabletu nie robi Nic zrobić (z wyjątkiem przeglądania wiadomości na Logcat: Yes, I am seeing this line). enter image description here

Co powinienem dodać więcej w styles.xml lub w kodzie, aby zobaczyć okno dialogowe dla tabletu jako DetailedFragment?

EDIT

Próbowałem rozwiązanie małe dziecko proponowaną (mieć DialogFragment zawierać mój początkowy fragment i pokazać go).Więc dodałem WrapperDetailedFragment:

public class WraperDetailedFragment extends DialogFragment { 
    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.wrap_detailed_fragment, container, false); 
    } 
} 

jej układ:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/root_container_dialog" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:orientation="vertical" > 

    <fragment 
     android:id="@+id/wrapped_fragment_id" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     class="com.myapps.sampleandroid.DetailedFragment" /> 

</LinearLayout> 

Kod z główną działalność zmienia się na:

private void decideToNext() { 
    String device = getString(R.string.device); 
    if ("normal".equalsIgnoreCase(device)) { 
     Intent intent = new Intent(this, DetailedActivity.class); 
     startActivity(intent); 
    } else if ("large".equalsIgnoreCase(device)) { 
     Log.d("SOME_TAG", "Yes, I am seeing this line ..."); 
     WraperDetailedFragment fragment = new WraperDetailedFragment(); 
     fragment.show(getSupportFragmentManager(), "MAGICAL_TAG"); 
    } 
} 

ale gdy próbuję dodać ten DialogFragment Następuje awaria:

android.view.InflateException: Binary XML file line #8: Error inflating class fragment 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:704) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
    at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12) 
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1082) 
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:304) 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676) 
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:746) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:489) 
    at android.view.LayoutInflater.inflate(LayoutInflater.java:396) 
    at com.myapps.sampleandroid.WraperDetailedFragment.onCreateView(WraperDetailedFragment.java:12) 
    at android.support.v4.app.Fragment.performCreateView(Fragment.java:1478) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:927) 
    at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1104) 
    at android.support.v4.app.BackStackRecord.run(BackStackRecord.java:682) 
    at android.support.v4.app.FragmentManagerImpl.execPendingActions(FragmentManager.java:1460) 
    at android.support.v4.app.FragmentManagerImpl$1.run(FragmentManager.java:440) 
    at android.os.Handler.handleCallback(Handler.java:615) 
    at android.os.Handler.dispatchMessage(Handler.java:92) 
    at android.os.Looper.loop(Looper.java:137) 
    at android.app.ActivityThread.main(ActivityThread.java:4745) 
    at java.lang.reflect.Method.invokeNative(Native Method) 
    at java.lang.reflect.Method.invoke(Method.java:511) 
    at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:786) 
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553) 
    at dalvik.system.NativeStart.main(Native Method) 
Caused by: java.lang.IllegalArgumentException: Binary XML file line #8: Duplicate id 0x7f050047, tag null, or parent id 0x0 with another fragment for com.myapps.sampleandroid.DetailedFragment 
    at android.support.v4.app.FragmentActivity.onCreateView(FragmentActivity.java:290) 
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:676) 
    ... 28 more 

Odpowiedz

21

Ten problem może być łatwo ustalony jeśli zamiast próbować zrobić Fragment wygląda jak DialogFragment Chciałbym spojrzeć z przeciwległego kąta: dokonać DialogFragment wygląda jak Fragment - przecież DialogFragment jest a Fragment!

Kluczem tej poprawki jest wywołanie lub nie DialogFragment.setShowsDialog();

więc zmieniając DetailedFragment do:

public class DetailedFragment extends DialogFragment { 

    private static final String ARG_SHOW_AS_DIALOG = "DetailedFragment.ARG_SHOW_AS_DIALOG"; 

    public static DetailedFragment newInstance(boolean showAsDialog) { 
     DetailedFragment fragment = new DetailedFragment(); 
     Bundle args = new Bundle(); 
     args.putBoolean(ARG_SHOW_AS_DIALOG, showAsDialog); 
     fragment.setArguments(args); 
     return fragment; 
    } 

    public static DetailedFragment newInstance() { 
     return newInstance(true); 
    } 

    @Override 
    public void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     Bundle args = getArguments(); 
     if (args != null) { 
      setShowsDialog(args.getBoolean(ARG_SHOW_AS_DIALOG, true)); 
     } 
    } 

    @Override 
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 
     return inflater.inflate(R.layout.detailed_fragment, container, false); 
    } 
} 

jego układ pozostaje jak to było, DetailedActivity zmiany:

public class DetailedActivity extends ActionBarActivity { 
    @Override 
    protected void onCreate(Bundle savedInstanceState) { 
     super.onCreate(savedInstanceState); 
     setContentView(R.layout.detailed_activity); 
     if (savedInstanceState == null) { 
      DetailedFragment fragment = DetailedFragment.newInstance(false); 
      getSupportFragmentManager().beginTransaction().add(R.id.root_layout_details, fragment, "Some_tag").commit(); 
     } 
    } 
} 

jego układ również:

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:id="@+id/root_layout_details" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" /> 

i aktywność rozmówca nie tylko:

private void decideToNext() { 
    String device = getString(R.string.device); 
    if ("normal".equalsIgnoreCase(device)) { 
     Intent intent = new Intent(this, DetailedActivity.class); 
     startActivity(intent); 
    } else if ("large".equalsIgnoreCase(device)) { 
     DetailedFragment fragment = DetailedFragment.newInstance(); 
     fragment.show(getSupportFragmentManager(), "Tablet_specific"); 
    } 
} 
1

OK, byłem tam i robiłem to. Aby utworzyć DialogFragment potrzebujesz układu zdefiniowanego w XML. Powiedz, że masz LinearLayout jako root. W tym LinearLayout można dodać fragment class="....", a po wyświetleniu DialogFragment, będzie to ten sam Fragment wyświetlany obok siebie na tablecie teraz wyświetlany w DialogFragment.

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical"> 
<fragment class="com.example.tqafragments.FeedFragment" android:id="@+id/feedFragment" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_weight="1"/> 
</LinearLayout> 

Tak jak w przypadku. I nadmuchać ten w DialogFragment

+0

Nie sądzę, że zrozumiałeś pytanie: Potrzebuję fragmentu, który będzie wyświetlany jako 'DialogFragment' dla tabletu, ale ten sam fragment musi pozostać non-DialogFragment dla smartfona.Podana przez Ciebie odpowiedź pokazuje, jak wyświetlić fragment - i tak dalej, myślę, że dostaniesz 'IllegalArgumentException', jeśli' FeedFragment' jest 'DialogFragment':' DialogFragment' nie może być dołączony do widoku kontenera'. DialogFragment można dodać tylko za pomocą metody dodawania/zamiany FragmentTransation po utworzeniu katalogu głównego. – gunar

+0

Wcale nie. Będziesz musiał zdefiniować inny układ dla małych telefonów i tabletów. Mam nadzieję, że wiesz, że możesz to zrobić :) W przypadku tabletów fragmenty będą wyświetlane obok siebie. To, co przegapiłeś, to ... '' DialogFragment' ** będzie zawierał ** 'Fragment'. –

+0

Więc jeśli rozumiem, że jesteś poprawny: sugerujesz, aby mieć DialogFragment i wewnątrz tego fragmentu, który chcę pokazać? – gunar

1

Aby DialogFragment pokaz jako zwykły Fragment, zadzwoń add() lub replace() używając identyfikatora zasobów do pojemnika fragmentu, np

beginTransaction().add(R.id.fragment_container, fragment) 

Ale aby wyświetlić DialogFragment jako okno dialogowe, zadzwoń pod numer add(fragment, "Fragment Tag"). Za kulisami powoduje to wywołanie do add(resId, fragment), ustawiając identyfikator zasobu dla kontenera fragmentu na 0, co powoduje, że DialogFragment ustawia swoją opcję na showAsDialog na true.

W konsekwencji możesz użyć fragmentu dialogowego jako okna dialogowego lub zwykłego fragmentu - w zależności od potrzeb - bez potrzeby tworzenia specjalnej logiki, aby to zrobić.