11

То, что я пытаюсь достичь, - иметь фрагмент, который на планшете отображается как DialogFragment, а на смартфоне он будет показан как обычный фрагмент. Я знаю, что уже есть similar post, но я не могу выполнить эту работу - примените стиль к фрагменту.Фрагмент Android-фрагмента как диалоговый фрагмент или обычный фрагмент

Чтобы показать вещи сверху вниз, 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 ничего особенного:

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

его расположение:

<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" /> 

и интересный 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); 
    } 
} 

... и его расположение:

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

В onCreateView я попытался установить пользовательский стиль, но это не похоже на работу для планшета.

Styling

Рез/значение/styles.xml содержит:

<resources> 

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

    <style name="MyDialogTheme" /> 

</resources> 

в то время как разреш/ценности-большой/styles.xml:

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

Я вложенный MyDialogTheme от Theme.Dialog, но, похоже, это не помогает.

На смартфоне при касании по пункту «NEXT» меню панели действий я вижу подробную деятельность (снимок из SG2): snapshot from an SG2

, а нажав на тот же пункт меню «NEXT» с планшета это Безразлично ничего не делайте (кроме просмотра сообщения на Logcat: Yes, I am seeing this line). enter image description here

Что нужно добавить еще в styles.xml или в код, чтобы увидеть DetailedFragment в качестве диалогового окна для планшета?

EDIT

Я попробовал решение маленький ребенок предложенный (иметь DialogFragment содержать мой начальный фрагмент и показать его).Таким образом, я добавил 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); 
    } 
} 

его расположение:

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

Код от MainActivity меняется:

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

, но когда я пытаюсь добавить DialogFragment Я получаю следующий сбой:

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 

ответ

21

Эта проблема может быть легко исправлена, если вместо того, чтобы пытаться сделать Fragment похожим на DialogFragment я бы смотреть с противоположного угла: сделать DialogFragment похожим на Fragment - в конце концов, DialogFragment является a Fragment!

Ключ данного исправления является вызов или нет DialogFragment.setShowsDialog();

Так меняется DetailedFragment к:

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

его расположение остается, как это было, DetailedActivity изменения:

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

его расположение также:

<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" /> 

и активность абонент делает только:

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

ОК, я был там и сделал это. Для создания DialogFragment вам нужен макет, определенный в XML. Скажем, для этого у вас есть LinearLayout как root. В этом LinearLayout вы можете добавить fragment class="....", и при отображении DialogFragment будет отображаться то же самое Fragment, которое вы отображали бок о бок на планшете, который теперь отображается в 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> 

Нравится так. И раздувать это в DialogFragment

+0

Я не думаю, что вы поняли вопрос: мне нужен фрагмент, который будет отображаться как «DialogFragment» для планшета, но тот же фрагмент должен оставаться не-DialogFragment для смартфона.Ответ, который вы предоставили, показывает, как отображать фрагмент - по крайней мере, я думаю, вы получите 'IllegalArgumentException', если' FeedFragment' является 'DialogFragment':' DialogFragment' не может быть прикреплен к представлению контейнера'. DialogFragment может быть добавлен только через метод добавления/замены FragmentTransation после создания корня. – gunar

+0

Совсем нет. Вам нужно будет определить разный макет для небольших телефонов и планшетов. Надеюсь, вы знаете, что можете это сделать :) Для планшетов фрагменты будут отображаться бок о бок. Что вы пропустили - это 'DialogFragment' ** будет содержать **« Фрагмент ». –

+0

Итак, если я понимаю вас правильно: вы предлагаете иметь DialogFragment и внутри него Фрагмент, который мне интересно показать? – gunar

1

Чтобы сделать DialogFragment шоу как обычный Fragment, вызовите add() или replace() используя идентификатор ресурса для контейнера фрагмента, например

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

Но чтобы диалоговое окно DialogFragment отображалось как диалог, вызовите add(fragment, "Fragment Tag"). За кулисами это приводит к вызову add(resId, fragment), устанавливая идентификатор ресурса для контейнера фрагмента равным 0, что приводит к тому, что DialogFragment устанавливает для параметра showAsDialog значение true.

Как следствие, вы можете использовать фрагмент диалога в качестве диалога или обычного фрагмента - в зависимости от ваших потребностей - без необходимости создавать какую-либо специальную логику для этого.

Смежные вопросы