22. Fragment – 이중 창 Fragment 목록 Fragment FragmentActivity1 findFragmentById(R.id. DetailFragment ) setContentView(R.layout. main )
23. Fragment – 단일 창 Fragment Fragment Activity1 Fragment Activity2 Fragment 목록 setContentView(R.layout. main ) findViewById(R.id. DetailFragment ) is NULL intent.setClass(getActivity(),Fragment2. class); startActivity(intent );
Starting from Android 1.6 and up developers can divide the Activities of their applications into subcomponents called Fragments. Fragments -- can be added, removed, replaced, and animated inside an Activity dynamically -- are modular and reusable across multiple Activities. Here we’ve got the updated version of the contacts app showing the list of contacts in a fragment on the left and the details of the selected contact in a fragment on the right.
Figure out what you want your fragments to look like on different size screens and different orientations on those screens. Take advantage of the qualifiers for size and layout. Think about your use-cases. Tablet experience is very different than smartphone experience
So this my dual pane application build against Android 3.0. Two layouts (landscape and portrait) each with two panes.
In each case we start with 2 fragments inside an activity. As I mentioned earlier, fragments cannot live outside an Activity. When you run your application the main activity will load the main resource file (main.xml) that defines the layout for the entire application. You then attach fragments together with findFragmentId(). In this case we are attaching the detail fragment to the listFragment.
So how do you get this with Honeycomb. This is a pretty broad brush list but it should point you in the right direction. For each fragment you’ll need to create a new class. You can do this inside one java file or create separate java files for each class. You need to import android.app.Fragment (as well as FragmentManager). The fragments extend the Fragment class instead of the Activity class. Then add your lifecycle calls. Next you should create resource files for each fragment defining the layout for that fragment. You’ll add the fragments to the application by adding the fragment tag to the applications XML file. Remember to give it an ID. Lastly you’ll update your main Activity by first importing the fragment package. You then load the application UI with findViewById() – same as you’ve always done. To communicate with the fragment you’ll call findFragmentById() and give it the ID you defined for that fragment. In our example we daisy chain the fragments so the listFragment communicates with the content fragment with a call to findFragmentId() from the list.
So this is what your Android project would look like after you’re done creating a dual pane layout with fragments using Android 3.0. You’ll have your main activity along with 2 or more fragments. In your resource folder you’ll have a layout for landscape and portrait (if you want it to look differently). Your layout for the application as a whole is still defined in your main.xml and each fragment then has their UI defined in their own XML files. The difference in layouts between landscape and portrait is mainly the direction the fragments are displayed in.
So lets walk through the code. The main.java file is your activity. I’ve defined FragmentsHCDemo to extend Activity. In the onCreate() I call setContentView() with the activities layout file. This loads the resource file that contains the <fragment> definitions. The fragments are instantiated as soon as the activity loads the layout.
The layout file itself has a LinearLayout as it’s container and 2 <fragment> tags, each one defining the class name of the fragment as well as the properties of the fragment. This is the layout file for the landscape mode so I need to specify the orientation to be horizontal. Otherwise the LinearLayout defaults to top-to-bottom. So take a look at the properties for the first fragment – my list fragment. It has an id, followed by a layout_width (which in landscape mode is 200dp) and layout_height (which is set to match the parent).
If we look at the portrait version of that layout file there are a few things that change. First the orientation is now vertical (or top-to-bottom). The width and height of the list also need to be reversed. If I had left it alone the list would have expanded to fill the parent and there would be no room for the detail fragment.
There are 2 fragment files. This is the listFragment. As you can see we need to extend the ListFragment. There’s also a new set of lifecycle calls for fragments, one of which is onActivityCreated(). This is called after the main activity has completed it’s onCreate() call. In here we create a list adapter the same way you would inside an activity. Along with that list adapter you need a callback to handle selecting each list item which we’ve done with onListItemClick(). This is where you need to attach to your detail fragment. Each time we select something from the list a call is made to findFragmentById() and we pass in the id of the detail fragment that was defined in the main.xml file. Once we’ve located it, we then call into the detail fragment to update the image.
Then if we look at the detail fragment, you are extending a Fragment, calling one of the other new lifecycle calls for fragments – onCreateView(), inflating the layout for that detail fragment, and setting the initial image. Below that is the routine to update the image every time a list item is selected. You are passing in the position of the selected list item, locating the appropriate drawable, and setting the ImageView to that drawable.
The layout files for each of the fragments is pretty straightforward. The listFragment only defines the textView for the items in the list. The detail fragment uses a FrameLayout as it’s container and defines an ImageView to hold the images.
So you’ve got this big screen and you want to take advantage of it with fragments. You can use the same views and viewgroups in a fragment that you use in an Activity. You don’t have to use a listFragment; you can have two fragments side-by-side. Be creative.
Don’t need a resource file since there is no UI Don’t need a fragment tag in the main activity either. However without that definition there is no longer an id associated with the fragment so you’ll need to use a “tag” to get to that fragment. Easier than using the raw Activity.onRetainNonConfigurationInstance() API
Programmatically, you still define your fragment by extending a Fragment. Then (working from the bottom up) the first time you need to use that fragment you would have to instantiate it with a call to new(). You would then attach to that fragment with a call to “add” and supply a name, or tag, for that fragment. Since it’s considered a transaction you need to surround it with beginTransaction() and commit(). Thereafter you can locate that fragment with a call to findFragmentByTag() supplying the name you gave it when you first added it.
So let’s say you want your app to look like this in landscape mode on ANY device (this happens to be on a XOOM)
And you want it to look like this in portrait mode (this happens to be an ATRIX)
To get your dual pane it’s pretty much the same logic as it is on Android 3.0. You need a main activity but in the Compatibility library it’s now called a “FragmentActivity”. You still need to create each fragment by subclassing the appropriate fragment type. You still need to define a UI for each fragment. And you still need to add a fragment tag to the main activities layout file. A call to findFragmentId() is used to locate and perform any operations on that fragment.
Single pane logic (for instance for portrait) gets interesting. First of all this way of displaying fragments is based on the orientation. So you’ll need to check whether you’re in portrait mode or not. If so instead of calling findFragmentById() from the listFragment you’ll start a new activity for the detail by way of intents. Since fragments can’t live outside of an Activity you need to define a FragmentActivity for each fragment.
In the end this is what your project will contain. You’ll have two FragmentActivites and two fragments. The main activity locates fragment1 with findFragmentById(). Fragment1 loads fragment2 by launching an intent to start the second activity. You landscape layout stays the same but your portrait layout for your activity only contains the fragment tag for the first fragment. When you call setContentView(), only one fragment is loaded.