Showing posts with label actionbar. Show all posts
Showing posts with label actionbar. Show all posts

Thursday, June 19, 2014

Navigation Drawer Icon in Action Bar without Using Drawer Layout

This post help us to get navigation drawer icon without android drawer layout in the Action Bar.

Enable action bar icon to support navigation drawer toggle.
// Set whether home should be displayed as an "up" affordance.
// Set this to true if selecting "home" returns up by a single level in your UI rather than back to the top level or front page.
getActionBar().setDisplayHomeAsUpEnabled(true);
//Enable or disable the "home" button in the corner of the action bar.
getActionBar().setHomeButtonEnabled(true);

We should be aware of navigation drawer before starting, navigation drawer helps user to bring the navigation drawer onto the screen by swiping from the left edge of the screen or by touching the application icon on the action bar.

On Tap of application icon, Navigation drawer opens by using DrawerLayout listeners, where ActionBarDrawerToggle supports us from toggling the drawer.

This class provides a handy way to tie together the functionality of DrawerLayout and the framework ActionBar to implement the recommended design for navigation drawers.

ActionBarDrawerToggle(Activity activity, DrawerLayout drawerLayout, int drawerImageRes, int openDrawerContentDescRes, int closeDrawerContentDescRes)

Construct a new ActionBarDrawerToggle.
The given Activity will be linked to the specified DrawerLayout. The provided drawer indicator drawable will animate slightly off-screen as the drawer is opened, indicating that in the open state the drawer will move off-screen when pressed and in the closed state the drawer will move on-screen when pressed.
String resources must be provided to describe the open/close drawer actions for accessibility services.
Parameters

activity The Activity hosting the drawer
drawerLayout The DrawerLayout to link to the given Activity's ActionBar
drawerImageRes A Drawable resource to use as the drawer indicator
openDrawerContentDescRes A String resource to describe the "open drawer" action for accessibility
closeDrawerContentDescRes A String resource to describe the "close drawer" action for accessibility

The third parameter is the drawable which we are seeing beside the action bar icon.

Now the question, How can we update the navigation drawer icon without DrawerLayout?

Just call updateNavigationDrawerIcon method after enabling the action bar methods.

public void updateNavigationDrawerIcon(Drawable drawable) {
Method setHomeAsUpIndicator;
           try {
           setHomeAsUpIndicator = ActionBar.class.getDeclaredMethod("setHomeAsUpIndicator",            Drawable.class);
           setHomeAsUpIndicator.invoke(getActionBar(), drawable);
           } catch (NoSuchMethodException e) {
                      Log.e("CHECK", "No Such Method");
                      View home = findViewById(android.R.id.home);
                      ViewGroup parent = (ViewGroup) home.getParent();
                      int childCount = parent.getChildCount();
                      if (childCount == 2) {
                                final View first = parent.getChildAt(0);
                                final View second = parent.getChildAt(1);
                               final View up = first.getId() == android.R.id.home ? second : first;
                                 ((ImageView) up).setImageDrawable(drawable);
                      }
           } catch (Exception e) {
           e.printStackTrace();
           }
}

On click of app icon, we will be invoking onOptionsItemSelected method.

@Override
public boolean onOptionsItemSelected(MenuItem item) {

           switch (item.getItemId()) {
           case android.R.id.home:
                      Log.d("CHECK", "Navigation Icon is selected");
                      // Use for slide from left to right
                      slide_me.toggleLeftDrawer();
                      break;
           }
           return super.onOptionsItemSelected(item);
}

Output:




Source Code
You can download the source code by Source Code Click Here.  This project is built using eclipse IDE. Unzip and import the project into Eclipse, it’s a good idea to use the Project by clean and rebuild from the project menu. It works in all API levels above 14.

Thanks for reading :) 
Whether this post is helpful?

Have something to add to this post? If you have any other quick thoughts/hints that you think people will find useful? Share it in the comments.

Tuesday, May 6, 2014

Fragment lifecycle with respect to its Activity

What is Fragment?

Fragment represents a behavior or a portion of user interface in an ActivityWe can combine multiple fragments in a single activity to build a multi-pane UI and reuse a fragment in multiple activities. 

The Fragment class has code that looks a lot like an Activity. It contains callback methods similar to an activity, such as onCreate()onStart()onPause(), andonStop(). In fact, if you're converting an existing Android application to use fragments, you might simply move code from your activity's callback methods into the respective callback methods of your fragment.

Fragment Lifecycle

Origin : http://developer.android.com/guide/components/fragments.html#Lifecycle

Fragment lifecycle with respect to its Activity

Fragment's lifecycle is tied to its owning activity and the normal flow of fragment in a activity.

1.    MainActivity onCreate
     Fragment onAttach
     Fragment onCreate
     Fragment onCreateView
     Fragment onViewCreated
     Fragment onActivityCreated
2.    MainActivity onStart
          Fragment onStart
3.    MainActivity onResume
          Fragment onResume
          Fragment onStop
4.    MainActivity onStop
          Fragment onDestroyView
          Fragment onDestroy
          Fragment onDetach
5.    MainActivity onDestroy

What happens? If we navigates to another activity from fragment and come back to main activity?

Here we have two scenarios, where fragment life cycle works.
1.    Activity is not destroyed when user leaves it.
2.    Activity got destroyed when user leaves it.
Activity Normal flow
Activity got destroyed
MainActivity onCreate
          Fragment onAttach
          Fragment onCreate
          Fragment onCreateView
          Fragment onViewCreated
          Fragment onActivityCreated
MainActivity onStart
          Fragment onStart
MainActivity onResume
          Fragment onResume
MainActivity onCreate
          Fragment onAttach
          Fragment onCreate
          Fragment onCreateView
          Fragment onViewCreated
          Fragment onActivityCreated
MainActivity onStart
          Fragment onStart
MainActivity onResume
          Fragment onResume
          Fragment onStop
MainActivity onStop
          Fragment onStop
MainActivity onStop
          Fragment onDestroyView
          Fragment onDestroy
          Fragment onDetach
MainActivity onDestroy
MainActivity onRestart
MainActivity onStart
          Fragment onStart
MainActivity onResume
          Fragment onResume
          Fragment onAttach
          Fragment onCreate
MainActivity onCreate
          Fragment onCreateView
          Fragment onViewCreated
          Fragment onActivityCreated
MainActivity onStart
          Fragment onStart
MainActivity onResume
          Fragment onResume

In the above differentiation, the 2nd and 3rd row tells the flow of life cycle of fragment with respect to its activity.
By this flow change, we should be aware in writing our business logics.

Why, we should be aware?

Example: Assume, we have a custom action bar header, we are modifying the header depend upon the fragment selection in the fragment.
The custom header is called in the MainActivity Oncreate method as follows
         ActionBar bar = getActionBar();
        if (bar != null) {
bar.setDisplayOptions(ActionBar.DISPLAY_HOME_AS_UP | ActionBar.DISPLAY_SHOW_CUSTOM | ActionBar.DISPLAY_SHOW_HOME | ActionBar.DISPLAY_USE_LOGO);
          bar.setCustomView(R.layout.custom_header);
        }

        // enable ActionBar app icon to behave as action to toggle nav drawer
        bar.setDisplayHomeAsUpEnabled(true);
        bar.setHomeButtonEnabled(true);

In fragment, the custom header is updated as follows.
Create instance of the activity in fragment to update the action bar header.
onAttach(Activity)called once the fragment is associated with its activity. So, we can assign our variable inside the onAttach
public MainActivity activity;
@Override
public void onAttach(Activity activity) {
          Log.d("CHECK", " Fragment onAttach");
      super.onAttach(activity);
      this.activity = (MainActivity) activity;
}

activity.updateActionBarHeader(activity.getTitle().toString());
Usually, we will be setting headers in onCreate of activity or fragment, Since onCreate(Bundle)called to do initial creation of the fragment.
Application launches and works fine, when we placed the updateActionBarHeader in onCreate, but when application navigated from fragment and returns back, the application crashes if the activity is destroyed and the exception thrown as follows.
FATAL EXCEPTION: main
java.lang.RuntimeException: Unable to start activity ComponentInfo {PACKAGE_NAME/MainActivity}: java.lang.NullPointerException
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2059)
          at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2084)
          at android.app.ActivityThread.access$600(ActivityThread.java:130)
          at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1195)
          at android.os.Handler.dispatchMessage(Handler.java:99)
          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.NullPointerException
          at MainActivity.updateActionBarHeader(MainActivity.java:232)
          at MainActivity$PlanetFragment.onCreate(MainActivity.java:276)
          at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:796)
          at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1035)
          at android.app.FragmentManagerImpl.moveToState(FragmentManager.java:1017)
          at android.app.FragmentManagerImpl.dispatchCreate(FragmentManager.java:1797)
          at android.app.Activity.onCreate(Activity.java:886)
          at MainActivity.onCreate(MainActivity.java:80)
          at android.app.Activity.performCreate(Activity.java:5008)
          at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1079)
          at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2023)
          ... 11 more

So, don't try to put the logic of updating action bar in onCreateView rather than onCreate of fragment and avoid the crash.

Thanks for reading :) 
Whether this post is helpful?

Have something to add to this post? If you have any other quick thoughts/hints that you think people will find useful? Share it in the comments.