Fragments: Why? How? and What For?

42df4bd18a5688739a6aa58a04cce043?s=47 Brenda Cook
January 20, 2016

Fragments: Why? How? and What For?

42df4bd18a5688739a6aa58a04cce043?s=128

Brenda Cook

January 20, 2016
Tweet

Transcript

  1. Fragments Why? How? What for?

  2. Who Needs Fragments?

  3. Who Needs Fragments? You do!

  4. Why?

  5. • Smaller View Controllers

  6. • Smaller View Controllers • Reusable UI & Logic Components

  7. • Smaller View Controllers • Reusable UI & Logic Components

    • Address device fragmentation
  8. • Smaller View Controllers • Reusable UI & Logic Components

    • Address device fragmentation • Decomposition of application code
  9. How do they work?

  10. Image Credit: Steve Pomeroy | github.com/xxv/android-lifecycle

  11. Image Credit: Lars Vogel | vogella.com

  12. onViewCreated() onViewStateRestored()

  13. Static vs Dynamic

  14. Adding Fragments Statically <fragment xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/puppy_list"
 android:name="com.kenodoggy.masterdetailflow.PuppyListFragment"
 android:layout_width="match_parent"
 android:layout_height="match_parent"


    android:layout_marginLeft="16dp"
 android:layout_marginRight="16dp"
 tools:context=".PuppyListActivity"
 tools:layout="@android:layout/list_content"/>
  15. Dynamically Adding Fragments Instantiation Rules you must know

  16. public MyFragment() {
 // Required empty public constructor
 } Default

    Constructor
  17. public static MyFragment newInstance(int position) {
 MyFragment fragment = new

    MyFragment();
 Bundle args = new Bundle();
 args.putInt(ARG_POSITION, position);
 fragment.setArguments(args);
 return fragment;
 } New Instances
  18. public static MyFragment newInstance(int position) {
 MyFragment fragment = new

    MyFragment();
 Bundle args = new Bundle();
 args.putInt(KEY_POSITION, position);
 fragment.setArguments(args);
 return fragment;
 } New Instances
  19. Adding a Fragment MyFragment fragment = MyFragment.newInstance(args);
 
 getFragmentManager().beginTransaction()
 .add(R.id.fragment_container,

    fragment)
 .commit();
  20. Adding a Fragment MyFragment fragment = MyFragment.newInstance(args);
 
 getFragmentManager().beginTransaction()
 .add(R.id.fragment_container,

    fragment)
 .commit();
  21. Replacing a Fragment MyFragment fragment = MyFragment.newInstance(args);
 
 getFragmentManager().beginTransaction()
 .replace(R.id.fragment_container,

    fragment)
 .commit();
  22. None
  23. Destruction

  24. Image Credit: Lars Vogel | vogella.com onSaveInstanceState()

  25. setRetainInstance(true) @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);
 
 //

    Retain this fragment across configuration changes.
 setRetainInstance(true);
 }
  26. Examples

  27. Dual / Single Pane Design aka Master / Detail

  28. None
  29. Specifying Layouts Based on Screen Properties

  30. Navigation Layout for Phone <fragment xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:id="@+id/puppy_list"
 android:name="com.kenodoggy.masterdetailflow.PuppyListFragment"
 android:layout_width="match_parent"


    android:layout_height="match_parent"
 android:layout_marginLeft="16dp"
 android:layout_marginRight="16dp"
 tools:context=".PuppyListActivity"
 tools:layout="@android:layout/list_content"/>
  31. Detail Layout for Phone <android.support.design.widget.CoordinatorLayout>
 <android.support.design.widget.AppBarLayout>
 <android.support.design.widget.CollapsingToolbarLayout>
 <android.support.v7.widget.Toolbar />
 </android.support.design.widget.CollapsingToolbarLayout>


    </android.support.design.widget.AppBarLayout> 
 <android.support.v4.widget.NestedScrollView
 android:id="@+id/puppy_detail_container"
 android:layout_width="match_parent"
 android:layout_height="match_parent"
 app:layout_behavior=“@string/appbar_scrolling_view_behavior"/> 
 </android.support.design.widget.CoordinatorLayout>

  32. None
  33. List/Detail Layout for Tablet <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
 xmlns:tools="http://schemas.android.com/tools"
 android:orientation="horizontal">
 
 <fragment


    android:id="@+id/puppy_list"
 android:name="com.kenodoggy.masterdetailflow.PuppyListFragment"
 android:layout_width="0dp"
 android:layout_height="match_parent"
 android:layout_weight="1"
 tools:layout="@android:layout/list_content"/>
 
 <FrameLayout
 android:id="@+id/puppy_detail_container"
 android:layout_width="0dp"
 android:layout_height="match_parent"
 android:layout_weight="3"/>
 
 </LinearLayout>
  34. Determining Which Layout to Display

  35. None
  36. None
  37. None
  38. None
  39. Dual or Single Pane? if (findViewById(R.id.puppy_detail_container) != null) {
 //

    The detail container view will be present only in the
 // large-screen layouts (res/values-large and
 // res/values-sw600dp). If this view is present, then the
 // activity should be in two-pane mode.
 mTwoPane = true;
 
 ... code specific to two pane layout
 }
  40. Tabbed ViewPager Using TabLayout

  41. None
  42. The Parent Activity Layout <android.support.design.widget.CoordinatorLayout>
 <android.support.design.widget.AppBarLayout>
 <android.support.v7.widget.Toolbar />
 
 <android.support.design.widget.TabLayout

    android:id="@+id/tabs"
 android:layout_width=“wrap_content" android:layout_height="wrap_content"
 app:tabMode="scrollable"/>
 
 </android.support.design.widget.AppBarLayout>
 
 <android.support.v4.view.ViewPager android:id="@+id/container"
 android:layout_width="match_parent" android:layout_height="match_parent"
 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
 
 </android.support.design.widget.CoordinatorLayout>
  43. The Parent Activity Layout <android.support.design.widget.CoordinatorLayout>
 <android.support.design.widget.AppBarLayout>
 <android.support.v7.widget.Toolbar />
 
 <android.support.design.widget.TabLayout

    android:id="@+id/tabs"
 android:layout_width=“wrap_content" android:layout_height="wrap_content"
 app:tabMode="scrollable"/>
 
 </android.support.design.widget.AppBarLayout>
 
 <android.support.v4.view.ViewPager android:id="@+id/container"
 android:layout_width="match_parent" android:layout_height="match_parent"
 app:layout_behavior="@string/appbar_scrolling_view_behavior" />
 
 </android.support.design.widget.CoordinatorLayout>
  44. Setting up our ViewPager 
 ViewPagerAdapter adapter = new ViewPagerAdapter(getSupportFragmentManager());


    
 /* add the Fragments to the ViewPagerAdapter */
 for(String title : mPuppyTitles) {
 adapter.addFrag(PuppyFragment.newInstance(index++), title);
 }
 
 mViewPager.setAdapter(adapter);
  45. Creating our PuppyFragment @Override
 public void onCreate(Bundle savedInstanceState) {
 super.onCreate(savedInstanceState);


    if (getArguments() != null) {
 mPageNumber = getArguments().getInt(ARG_POSITION);
 }
 }
  46. Loading the UI @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,


    Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.fragment_puppy, container, false);
 
 int imageId = getResources().getIdentifier(mPuppyImages[mPageNumber],
 "drawable", getActivity().getPackageName()); 
 ImageView image = (ImageView) view.findViewById(R.id.puppy_picture);
 image.setImageResource(imageId);
 
 return view;
 }
  47. Loading the UI @Override
 public View onCreateView(LayoutInflater inflater, ViewGroup container,


    Bundle savedInstanceState) {
 View view = inflater.inflate(R.layout.fragment_puppy, container, false);
 
 int imageId = getResources().getIdentifier(mPuppyImages[mPageNumber],
 "drawable", getActivity().getPackageName()); 
 ImageView image = (ImageView) view.findViewById(R.id.puppy_picture);
 image.setImageResource(imageId);
 
 return view;
 }
  48. Navigation Drawer

  49. None
  50. None
  51. Fragment fragment = DetailFragment.newInstance(puppy, position);
 
 FragmentManager fragmentManager = getFragmentManager();


    FragmentTransaction transaction = fragmentManager.beginTransaction();
 // do replace and commit operation
 transaction.replace(R.id.detail_container, fragment).commit();
  52. Fragment fragment = DetailFragment.newInstance(puppy, position);
 
 FragmentManager fragmentManager = getFragmentManager();


    FragmentTransaction transaction = fragmentManager.beginTransaction();
 // do replace, add to backstack and commit operation
 transaction.replace(R.id.detail_container, fragment) .addToBackStack(“details”) // optional name for this back stack state, or null .commit();
  53. Going Back • Fragment: popBackStack() • Activity: onBackPressed()

  54. DialogFragment

  55. Constructing a DialogFragment Two ways:

  56. Constructing a DialogFragment Two ways: @Override onCreateView()

  57. Constructing a DialogFragment Two ways: @Override onCreateDialog() @Override onCreateView()

  58. public class SampleDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {
 @Override
 public

    Dialog onCreateDialog(Bundle savedInstanceState) {
 View view = getActivity() .getLayoutInflater() .inflate(R.layout.fragment_sample_dialog, null);
 
 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 
 return(builder
 .setView(view)
 .setTitle(title)
 .setPositiveButton(R.string.close, null)
 .create());
 }
 }
  59. public class SampleDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {
 @Override
 public

    Dialog onCreateDialog(Bundle savedInstanceState) {
 View view = getActivity() .getLayoutInflater() .inflate(R.layout.fragment_sample_dialog, null);
 
 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 
 return(builder
 .setView(view)
 .setTitle(title)
 .setPositiveButton(R.string.close, null)
 .create());
 }
 }
  60. public class SampleDialogFragment extends DialogFragment implements DialogInterface.OnClickListener {
 @Override
 public

    Dialog onCreateDialog(Bundle savedInstanceState) {
 View view = getActivity() .getLayoutInflater() .inflate(R.layout.fragment_sample_dialog, null);
 
 AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());
 
 return(builder
 .setView(view)
 .setCustomTitle(title)
 .setPositiveButton(R.string.close, null)
 .create());
 }
 }
  61. Showing your DialogFragment SampleDialogFragment frag = SampleDialogFragment.newInstance(args); frag.show(getFragmentManager(), SampleDialogFragment.TAG);

  62. 
 return(builder
 .setTitle(title) .setMessage(“Dialog Message”)
 .setPositiveButton(R.string.close, null)
 .create());


  63. None
  64. Dismissing a DialogFragment

  65. Communicating with the Parent Activity

  66. Define an Interface public interface OnDialogDismissed {
 void onDialogDismissed(String whichSalutation);


    }
  67. @Override
 public void onAttach(Activity activity) {
 super.onAttach(activity);
 try {
 mDialogDismissedCallback

    = (OnDialogDismissed)activity;
 } catch (ClassCastException cce) {
 Log.e("Error", getClass().getSimpleName() + ", calling Activity must implement OnDialogDismissed");
 }
 }
  68. public class MainActivity extends AppCompatActivity implements SampleDialogFragment.OnDialogDismissed {
 // ...

    other methods and implementation not shown
 @Override
 public void onDialogDismissed(String whichSalutation) {
 if (whichSalutation.equals(SampleDialogFragment.GOODBYE)) {
 Toast.makeText(this, "Thank you!", Toast.LENGTH_SHORT).show();
 }
 }
 }
  69. @Override
 public void onClick(DialogInterface dialog, int which) {
 // display

    a toast when the dialog is dismissed for GOODBYE only
 if (mSalutation.equals(GOODBYE)) {
 mDialogDismissedCallback.onDialogDismissed(GOODBYE);
 }
 }
  70. None
  71. Thank you Source Code: github.com/kenodoggy/ Slides: speakerdeck.com/kenodoggy/ Twitter @kenodoggy g+

    +BrendaCook_kenodoggy