Hello Friends,
Here we are going to create advanced drawer with custom layout and dynamic fragment loading on each drawer item click.
To learn how to add simple drawer in Android refer this tutorial:
http://dharmangsoni.blogspot.in/2013/11/simple-navigational-drawer-layout-in.html
drawer_item_layout.xml
Here you can see some @color and @drawable resources. We have created our resources to handle each item background and textcolor. For that you need to create following files:
@color
Create new folder in /res/color and create drawer_color_selector.xml
Here we are going to create advanced drawer with custom layout and dynamic fragment loading on each drawer item click.
To learn how to add simple drawer in Android refer this tutorial:
http://dharmangsoni.blogspot.in/2013/11/simple-navigational-drawer-layout-in.html
What we are going to develop?
What we required?
- Custom drawer row view
- Drawer Item handler class
- Drawer ListView custom adapter to handle each custom row
- Color selector when user click on drawer item
- Custom ImageView for handling tint color (image color) when drawer item selected
Creating custom drawer row layout xml file:
Here we required two different layout; one for grouping and second for our row item.
drawer_item_group_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ffffff" android:orientation="vertical" > <TextView android:id="@+id/txvDrawerItemTitle" style="?android:attr/textAppearanceSmall" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:paddingBottom="2dp" android:paddingLeft="10dp" android:paddingTop="10dp" android:text="Title" android:textAllCaps="true" android:textColor="#4B4B4D" android:textStyle="bold" /> <View android:id="@+id/viewDrawerGroupView" android:layout_width="match_parent" android:layout_height="1dp" android:background="#BEBEBE" /> </LinearLayout>
drawer_item_layout.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:custom="http://schemas.android.com/apk/res/com.dharmangsoni.customdrawer" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="@drawable/drawer_item_selector" android:orientation="horizontal" android:weightSum="2" > <com.dharmangsoni.drawer.DrawerIconView android:id="@+id/imgDrawerItemIcon" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="8dp" android:layout_marginLeft="8dp" android:layout_marginRight="0dp" android:layout_marginTop="8dp" android:src="@drawable/ic_action_inbox" android:visibility="gone" custom:tint="@color/drawer_color_selector" /> <View android:id="@+id/drawerTagColor" android:layout_width="5dp" android:layout_height="match_parent" android:background="#ffffff" android:visibility="gone" /> <TextView android:id="@+id/txvDrawerItemTitle" style="?android:attr/textAppearanceMedium" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="2" android:gravity="center_vertical" android:padding="10dp" android:text="Title" android:textColor="@color/drawer_color_selector" /> <TextView android:id="@+id/txvDrawerItemCounter" style="?android:attr/textAppearanceSmall" android:layout_width="50dp" android:layout_height="match_parent" android:gravity="center" android:padding="10dp" android:text="99+" android:textColor="@color/drawer_color_selector" android:textStyle="bold" /> </LinearLayout>
Here you can see some @color and @drawable resources. We have created our resources to handle each item background and textcolor. For that you need to create following files:
@color
Create new folder in /res/color and create drawer_color_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_activated="true" android:color="#ffffff"/> <item android:color="#4B4B4D"/> </selector>
@drawable
create new folder in /res/drawable and create following three files:
drawer_item_focused.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:angle="270" android:endColor="#33B5E5" android:startColor="#33B5E5" /> </shape>
drawer_item_pressed.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle" > <gradient android:angle="270" android:endColor="#8bd7f0" android:startColor="#8bd7f0" /> </shape>
drawer_item_selector.xml
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:drawable="@drawable/drawer_item_pressed" android:state_activated="false" android:state_pressed="true"/> <item android:drawable="@drawable/drawer_item_focused" android:state_activated="true"/> </selector>
This selector will change row color when you click on the drawer item and with selector when item is selected @color selector will change the content color as per selection of the drawer item.
Now we are ready with our layout (resources xml)
Now we create our required class files:
1. DrawerItem.java
Drawer item stores each drawer item details. Title, Group info, icon, tag color and also Fragment instance. Here it is,
package com.dharmangsoni.drawer; import android.support.v4.app.Fragment; import android.widget.AdapterView.OnItemClickListener; public class DrawerItem { private int id = 0; private String title = ""; private int counter = 0; private boolean isGroupTitle = false; private int icon = 0; private String tagColor = null; private Fragment fragment = null; public DrawerItem(int id, String title, Fragment fragment, int counter) { this.id = id; this.title = title; this.counter = counter; this.fragment = fragment; } public DrawerItem(int id, String title, Fragment fragment, int counter, int icon) { this.id = id; this.title = title; this.counter = counter; this.icon = icon; this.fragment = fragment; } public DrawerItem(int id, String title, Fragment fragment, int counter, String tagColor) { this.id = id; this.title = title; this.counter = counter; this.tagColor = tagColor; this.fragment = fragment; } public DrawerItem(int id, String title, boolean isGroupTitle) { this.id = id; this.title = title; this.isGroupTitle = isGroupTitle; } public DrawerItem(int id, String title, int counter, boolean isGroupTitle) { this.id = id; this.title = title; this.counter = counter; this.isGroupTitle = isGroupTitle; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getTitle() { return title; } public void setTitle(String title) { this.title = title; } public int getCounter() { return counter; } public void setCounter(int counter) { this.counter = counter; } public void isGroupTitle(boolean flag) { this.isGroupTitle = flag; } public boolean isGroupTitle() { return this.isGroupTitle; } public void setIcon(int resource) { icon = resource; } public int getIcon() { return icon; } public void setTagColor(String tagColor) { this.tagColor = tagColor; } public String getTagColor() { return this.tagColor; } public Fragment getFragment() { return fragment; } public void setFragment(Fragment fragment) { this.fragment = fragment; } public interface DrawerItemClickListener extends OnItemClickListener { } }
This class contain all getter setters and also some required constructor for setting group, tag color, counter and fragments.
2. DrawerIconView.java
This class contain ImageView but with dynamic tint color changing. ImageView does not support dynamic selector tint color so we have created custom image view for showing icon.
We uses our custom attribute as tint for this ImageView.
To create custom attribute for control create attrs.xml file in /res/values/ and create file named attrs.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <declare-styleable name="DrawerIconView"> <attr name="tint" format="reference|color" /> </declare-styleable> </resources>
package com.dharmangsoni.drawer; import android.content.Context; import android.content.res.ColorStateList; import android.content.res.TypedArray; import android.util.AttributeSet; import android.widget.ImageView; import com.dharmangsoni.customdrawer.R; public class DrawerIconView extends ImageView { private ColorStateList tint; public DrawerIconView(Context context) { super(context); } public DrawerIconView(Context context, AttributeSet attrs) { super(context, attrs); init(context, attrs, 0); } public DrawerIconView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); init(context, attrs, defStyle); } private void init(Context context, AttributeSet attrs, int defStyle) { TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.DrawerIconView); tint = a.getColorStateList(R.styleable.DrawerIconView_tint); a.recycle(); } @Override protected void drawableStateChanged() { super.drawableStateChanged(); if (tint != null && tint.isStateful()) { updateTintColor(); } } public void setColorFilter(ColorStateList tint) { this.tint = tint; super.setColorFilter(tint.getColorForState(getDrawableState(), 0)); } private void updateTintColor() { int color = tint.getColorForState(getDrawableState(), 0); setColorFilter(color); } }3. DrawerAdapter.java
The drawer adapter; is responsible for handling each row view and creating custom view as per drawer item requirement.
package com.dharmangsoni.drawer; import java.util.ArrayList; import java.util.List; import android.content.Context; import android.graphics.Color; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ArrayAdapter; import android.widget.TextView; import com.dharmangsoni.customdrawer.R; public class DrawerAdatper extends ArrayAdapterNow we are ready with custom Drawer. We just need to create item list and pass it to custom drawer adapter and just implement our item click listener.{ List mObjects = null; Context mContext = null; int mResource = 0; int mGroupResource = 0; public DrawerAdatper(Context context, int item_resource, int item_group_resource, List objects) { super(context, item_resource, objects); mObjects = new ArrayList (objects); mContext = context; mResource = item_resource; mGroupResource = item_group_resource; } @Override public View getView(int position, View convertView, ViewGroup parent) { View mView = convertView; DrawerItem item = mObjects.get(position); LayoutInflater inflater = (LayoutInflater) mContext .getSystemService(Context.LAYOUT_INFLATER_SERVICE); if (item.isGroupTitle()) { mView = inflater.inflate(mGroupResource, parent, false); } else { mView = inflater.inflate(mResource, parent, false); } // Setting title TextView txvTitle = (TextView) mView .findViewById(R.id.txvDrawerItemTitle); txvTitle.setText(item.getTitle()); if (!item.isGroupTitle()) { // setting counter TextView txvCounter = (TextView) mView .findViewById(R.id.txvDrawerItemCounter); if (item.getCounter() > 0) { String counter_string = (item.getCounter() > 99) ? "99+" : item .getCounter() + ""; txvCounter.setText(counter_string); } else { txvCounter.setVisibility(View.GONE); } DrawerIconView imgItemIcon = (DrawerIconView) mView .findViewById(R.id.imgDrawerItemIcon); if (item.getIcon() != 0) { imgItemIcon.setVisibility(View.VISIBLE); imgItemIcon.setImageDrawable(mContext.getResources() .getDrawable(item.getIcon())); } View tagColorview = (View) mView.findViewById(R.id.drawerTagColor); if (item.getTagColor() != null) { tagColorview.setBackgroundColor(Color.parseColor(item .getTagColor())); tagColorview.setVisibility(View.VISIBLE); } else { tagColorview.setVisibility(View.GONE); } } return mView; } }
Here I create only one Fragment to handle each item click but pass different position to bundle.
DetailFragment.java
package com.dharmangsoni.customdrawer; import android.os.Bundle; import android.support.v4.app.Fragment; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.TextView; public class DetailFragment extends Fragment { View mView = null; @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { mView = inflater.inflate(R.layout.fragment_detail, container, false); Bundle bundle = getArguments(); if (bundle != null) { TextView txvDescription = (TextView) mView .findViewById(R.id.txvDescription); txvDescription.setText(bundle.getString("drawer_title")); } return mView; } }
fragment_detail.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:background="#ffffff" android:orientation="vertical" > <TextView android:id="@+id/txvDescription" style="?android:attr/textAppearanceLarge" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:text="Drawer Item Clicked" android:textAllCaps="true" android:textColor="#4B4B4D" android:textStyle="bold" /> </LinearLayout>
Now, it time to create drawer in MainActivity.java
package com.dharmangsoni.customdrawer; import java.util.ArrayList; import java.util.List; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.app.ActionBarDrawerToggle; import android.support.v4.app.Fragment; import android.support.v4.app.FragmentActivity; import android.support.v4.widget.DrawerLayout; import android.view.MenuItem; import android.view.View; import android.widget.AdapterView; import android.widget.ListView; import com.dharmangsoni.drawer.DrawerAdatper; import com.dharmangsoni.drawer.DrawerItem; public class MainActivity extends FragmentActivity implements DrawerItem.DrawerItemClickListener { String mTitle = ""; String mDrawerTitle = ""; ListView mDrawerList = null; DrawerAdatper mAdatper = null; DrawerLayout mDrawerLayout = null; Integer mDrawerItemSelectedPosition = -1; ActionBarDrawerToggle mDrawerToggle = null; ListmDrawerItems = new ArrayList (); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mTitle = getResources().getString(R.string.app_name); mDrawerTitle = getResources().getString(R.string.drawer_open); mDrawerLayout = (DrawerLayout) findViewById(R.id.drawer_layout); mDrawerList = (ListView) findViewById(R.id.drawer_list); mDrawerToggle = new ActionBarDrawerToggle(this, mDrawerLayout, R.drawable.ic_drawer, R.string.drawer_open, R.string.app_name) { @Override public void onDrawerClosed(View drawerView) { super.onDrawerClosed(drawerView); setTitle(mTitle); } @Override public void onDrawerOpened(View drawerView) { super.onDrawerOpened(drawerView); setTitle(mDrawerTitle); } }; mDrawerLayout.setDrawerListener(mDrawerToggle); getActionBar().setHomeButtonEnabled(true); getActionBar().setDisplayHomeAsUpEnabled(true); setDrawerItemList(); } private DetailFragment getFragment(String desc) { DetailFragment frag = new DetailFragment(); Bundle bundle = new Bundle(); bundle.putString("drawer_title", desc); frag.setArguments(bundle); return frag; } private void setDrawerItemList() { // Messages mDrawerItems.add(new DrawerItem(1, "Messages", true)); mDrawerItems.add(new DrawerItem(2, "Inbox", getFragment("Inbox"), 150, R.drawable.ic_action_inbox)); mDrawerItems.add(new DrawerItem(3, "To: me", getFragment("To: me"), 0, R.drawable.ic_action_user)); mDrawerItems.add(new DrawerItem(4, "To-do", getFragment("To-do"), 0, R.drawable.ic_action_todo)); mDrawerItems.add(new DrawerItem(5, "Archives", getFragment("Archives"), 0, R.drawable.ic_action_archive)); // Groups mDrawerItems.add(new DrawerItem(6, "My Groups", true)); mDrawerItems .add(new DrawerItem(7, "Join Group", getFragment("Join Group"), 0, R.drawable.ic_action_social_group)); mDrawerItems.add(new DrawerItem(8, "R&D", getFragment("R&D"), 0, "#218559")); mDrawerItems.add(new DrawerItem(9, "HR Policies", getFragment("HR Policies"), 5, "#192823")); mDrawerItems.add(new DrawerItem(10, "Company News", getFragment("Company News"), 0, "#FF8800")); // Notes mDrawerItems.add(new DrawerItem(11, "Notes", true)); mDrawerItems.add(new DrawerItem(12, "All Notes", getFragment("All Notes"), 5, R.drawable.ic_menu_notes)); mDrawerItems.add(new DrawerItem(13, "Archives", getFragment("Archives"), 0, R.drawable.ic_action_archive)); mDrawerItems.add(new DrawerItem(14, "New", getFragment("New"), 0, "#9933CC")); mDrawerItems.add(new DrawerItem(15, "Today", getFragment("Today"), 0, "#669900")); mDrawerItems.add(new DrawerItem(16, "This Week", getFragment("This Week"), 0, "#FF8800")); } @Override public void onStart() { super.onStart(); mAdatper = new DrawerAdatper(this, R.layout.drawer_item_layout, R.layout.drawer_item_group_layout, mDrawerItems); mDrawerList.setAdapter(mAdatper); mDrawerList.setOnItemClickListener(this); } @Override public boolean onOptionsItemSelected(MenuItem item) { if (mDrawerToggle.onOptionsItemSelected(item)) { return true; } return super.onOptionsItemSelected(item); } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); mDrawerToggle.onConfigurationChanged(newConfig); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); mDrawerToggle.syncState(); } @Override public void onItemClick(AdapterView adapter, View view, int position, long id) { DrawerItem item = mDrawerItems.get(position); if (!item.isGroupTitle()) { mDrawerItemSelectedPosition = position; Fragment fragment = item.getFragment(); getSupportFragmentManager().beginTransaction() .replace(R.id.frame_container, fragment).commit(); } mDrawerList.setItemChecked(mDrawerItemSelectedPosition, true); mDrawerLayout.closeDrawers(); } }
In this, setDrawerItemList() will set each drawer item with getFragment() which create fragment instance for each row.
Here is full source code of this application:
https://www.dropbox.com/s/ghnly2861e2au0l/AdvanceDrawer.tar.gz
Enjoy.. :)
No comments:
Post a Comment