Sunday, May 25, 2014

Android Custom Navigation Drawer Using ExpandableListView with Highlight for selected item

This post is improvements to the previous posts discussed on customization of navigation drawer and highlighting specific row of expandable listview.

Since there are few comments regarding the highlight of expandable list view post, thought to show with new post using custom navigation drawer. But how can we see the highlight of the expandable list view in handset, let’s take navigation drawer and customize it to use expandable list view.

Before starting, I have faced few problems before starting expandablelistview and few questions are shown below. They are?
1.   How and why onchildclicklistener won’t respond but ongroupclicklistener responding?
2.   Whether we can have different background to the group view and child view?
3.   How to highlight the group row or child row on selecting?
4.   How to give the feedback on selection of other row when there is a highlight shown on the other row?

Let’s start knowing the solution for the questions faced.
1.   How to get respond for OnChildClickListener and where will be the problem?
Solution: return true in isChildSelectable method of custom adapter.
Reason: When we extend BaseExpandableListAdapter of ExpandableListView adapter, we will be forced to override few methods. In one of the abstract method, we have isChildSelectable(int groupPosition, int childPosition) which in turn returns false default when we implement. Since it is false, we are unable to get respond OnChildClickListener. Turn it true to solve the porblem.

2.   Whether we can have different backgrounds to group and child views?
Solution: Yes
Reason: use custom adapter for expandablelistview and override getGroupView and getChildView method, and use different inflater.inflate xml’s to achieve it.

Create 2 layouts, one for group view and other for child view, let say as custom_list_view.xml and custom_list_view_child.xml
Inflate the layouts in the respective methods of getGroupView and getChildView and add android:background=" " to the layout.

3.   How to highlight the respective rows?
Solution: By using drawable xml’s and ItemChecked method of ExpandableListView.
Reason: drawable xml specify which color has to be shown on active of row and ItemChecked method specify which row has to be highlighted.

4.   How to give feedback for other rows in the list view?
Solution: By adding state_pressed item in the drawable xml’s.
Reason: Since the drawable xml is mapped to the layout, the action of the row is handled by the drawable xml. So, by adding state_pressed in the xml, we can get feedback when user press on the other row of the xml.

Source Code
You can download the source code by clicking 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.

Output
We can see, all four question answered in the below image.
Customized Navigation Drawer
Background color's : White for Group View and Orange for Child Views.
Highlighted Color : Blue
Feedback Color : Green




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.

Wednesday, May 21, 2014

Android: Solution for Custom Navigation Drawer not responding to Click

This post is about to solve and share the issue of navigation drawer when there is no action of the items of the list view.

Why the navigation drawer is not responding to the click's ? :-?

First we should know few information of navigation drawer.
What is Navigation Drawer? How to customize it? and lot more…

What is Navigation Drawer?
The navigation drawer is a panel that displays the app’s main navigation options on the left edge of the screen. It is hidden most of the time, but is revealed when the user swipes a finger from the left edge of the screen or, while at the top level of the app, the user touches the app icon in the action bar.

To add a navigation drawer, declare your user interface with a DrawerLayout object as the root view of your layout. Inside the DrawerLayout, add one view that contains the main content for the screen (your primary layout when the drawer is hidden) and another view that contains the contents of the navigation drawer.

What is DrawerLayout?
DrawerLayout acts as a top-level container for window content that allows for interactive "drawer" views to be pulled out from the edge of the window.

How to customize the navigation drawer?

Since the drawer layout adds only two views, and one view contains content of the screen and other view contains the navigation drawer content. So, we can use only two views in customization also.

Foe Eg: android example looks like this.


    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   
   
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
   
    android:id="@+id/left_drawer"
        android:layout_width="240dp"
        android:layout_height="match_parent"
        android:layout_gravity="start"
        android:choiceMode="singleChoice"
        android:divider="@android:color/transparent"
        android:dividerHeight="0dp"
        android:background="#111"/>



Customization example follows as:


    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">
   
   
        android:id="@+id/content_frame"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
    <!-- The navigation drawer →
<LinearLayout android:id="@+id/drawer_view"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:layout_gravity="start"
              android:background="@android:color/white"
              android:orientation="vertical" >
                android:id="@+id/left_drawer"
                    android:layout_width="240dp"
                    android:layout_height="match_parent"
                    android:layout_gravity="start"
                    android:choiceMode="singleChoice"
                    android:divider="@android:color/transparent"
                    android:dividerHeight="0dp"
                    android:background="#111"/>
</LinearLayout>



When we try to use the custom navigation drawer, there is scope where your navigation drawer linear layout change the view not being front, even the view is shown as front, we can call as Z ordering.

What is Z order?
The views are added in the group, should be order in the tree.

This scenario we can face in android 2.3 versions (gingerbread) when we scroll navigation drawer, then we won’t have action on list view of the navigation drawer. 

Finally we came to the issue what we are discussing about while start of the post, let’s look how to solve the issue below.

*-:)Issue is regarding the Z order of the view.

Then How to solve this Z order :?:

We should know about the bringToFront() method of View Class. Which solves our problem.

Know, we will use the above method in the scroll listener of list view, by calling the bringToFront() of the list and then requestLayout() of the drawer when the scroll states  is idle as shows

mDrawerList.setOnScrollListener(new OnScrollListener() {
           
            @Override
           public void onScrollStateChanged(AbsListView view, int scrollState) {
                       if (scrollState == SCROLL_STATE_IDLE) {
                                 mDrawerList.bringToFront();
                                    mDrawerLayout.requestLayout();
                        }               
            }
           
            @Override
            public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
      }
});

Issue is fixed...:-bd
Hope you have enjoyed by reading post...:smile: 


Improvements

If you want to see an example of customizing navigation drawer then, see Custom Navigation Drawer This example supports from API levels.

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. 

Thursday, May 15, 2014

Solution: android.util.AndroidRuntimeException: requestFeature() must be called before adding content.

android.util.AndroidRuntimeException: requestFeature() must be called before adding content
at com.android.internal.policy.impl.PhoneWindow.requestFeature(PhoneWindow.java:249)
at com.android.internal.app.AlertController.installContent(AlertController.java:234)
            at android.app.AlertDialog.onCreate(AlertDialog.java:337)
            at android.app.Dialog.dispatchOnCreate(Dialog.java:361)
            at android.app.Dialog.show(Dialog.java:262)

The following exception occurred when show() method of alertdialog box called.

The main causes is not show() of alertbox. Let’s look the source code

// AlertDialog.Builder used to create the alert box.

AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(this);
alertDialogBuilder.setIcon(R.drawable.ic_launcher);
alertDialogBuilder.setTitle("Full Screen...");
alertDialogBuilder.setMessage("Are you sure?");
alertDialogBuilder.setNeutralButton("OK",
                   new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int which) {
                                      dialog.cancel();
}
});
                       
// Creates a AlertDialog with the arguments supplied to this builder. It does not show() the dialog.

AlertDialog alertDialog = alertDialogBuilder.create();

// Retrieve the current Window for the activity.
// Set the flags of the window, as per the WindowManager.LayoutParams flags.
// Window flag FLAG_FULLSCREEN: hide all screen decorations (such as the status bar) while this window is displayed.

alertDialog.getWindow().setFlags(
                   WindowManager.LayoutParams.FLAG_FULLSCREEN,
                   WindowManager.LayoutParams.FLAG_FULLSCREEN);

int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION
                   | View.SYSTEM_UI_FLAG_FULLSCREEN;


// Retrieve the top-level window decor view (containing the standard window frame/decorations and the client's content inside of that), which can be added as a window to the window manager. Request that the visibility of the status bar or other screen/window decorations be changed.
alertDialog.getWindow().getDecorView().setSystemUiVisibility(uiOptions);

// Dialog is shown.
alertDialog.show();


Exception is occurred due to the getDecorView method, before showing the alertdialog to the user; we are trying to add content.

To solve the exception, just call the getDecorView after the alertDialog.show();

Before: (AndroidRuntimeException occurred)

alertDialog.getWindow().getDecorView().setSystemUiVisibility(uiOptions);

alertDialog.show();


After: (No Exception)

alertDialog.show();

alertDialog.getWindow().getDecorView().setSystemUiVisibility(uiOptions);


What is getDecorView()?

DecorView is nothing but View. This is an abstract method of Window class.

It retrieves the top-level window decor view, which can be added as a window to the window manager.

Where we can see getDecorView() in application?

When we call findViewById (int id), It finds a view that was identified by the id attribute from the XML that was processed in onCreate(Bundle). This will implicitly call getDecorView() for us, with all of the associated side-effects.

setSystemUiVisibility: This method is used to put the over device UI into temporary modes where the user's attention is focused more on the application content, by dimming or hiding surrounding system affordances.

When Android came up with Full-screen Immersive mode feature, the usage of setSystemUiVisibility became more popular. Where this feature is giving new ways to build beautiful apps by full-bleed UIs reaching end to end of the screen, by hiding all the system UI’s such as status bar and navigation bar, but the user swipes screen then there will be display of Semi-transparent bars which temporarily appear and then hide again.


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.