Material Design ListView Header With Xamarin.Android
As we know android always improves his weakness in his
design but since Android 5 was introduced the Material design was created to
fix that and now no only we can create useful Android apps now we are able to
create beautiful apps too, in this tutorial we will create a simple listview
with an awesome Material Design Header using backward libraries to support old
android versions.
So lets start.
First download these two libs from nuget
Floating Action Button for Xamarin.Android
Xamarin Support Library v7 AppCompat
After add these libraries to the project we need to add these
3 files to our Layout folder
“FakeHeader.axml” Contains the fake detail header you can
customize it with the elements that you want
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="wrap_content"> <RelativeLayout android:id="@+id/header_container" android:layout_width="match_parent" android:layout_height="@dimen/header_height" android:layout_marginBottom="30dp" android:background="@drawable/background"> <RelativeLayout android:id="@+id/header_infos_container" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:padding="16dp"> <TextView android:id="@+id/header_title" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_toRightOf="@+id/header_picture" android:text="Toolbar Title" android:textColor="@android:color/white" /> <TextView android:id="@+id/header_subtitle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/header_title" android:layout_toRightOf="@+id/header_picture" android:text="Toolbar Subtitle" android:textColor="@android:color/white" /> </RelativeLayout> </RelativeLayout> <com.refractored.fab.FloatingActionButton android:id="@+id/header_fab" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="bottom|right" android:src="@android:drawable/ic_dialog_info" android:layout_marginLeft="10dp" android:layout_marginBottom="5dp" android:layout_marginRight="10dp" android:background="@android:color/transparent" /> </FrameLayout>
“toolbar.xaml” Simple support toolbar V7 implementation
<?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" android:layout_height="@dimen/action_bar_height" local:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" local:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
“Main.axml” Contains the UI for our main activity
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> <ListView android:minWidth="25px" android:minHeight="25px" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@+id/listView1" android:scrollbars="none" /> <include android:id="@+id/toolbar" layout="@layout/toolbar" /> </FrameLayout>
Now we need to set the Colors, Dimensions and Styles
Material Design Like.
In our Values folder we need to add this 3 files.
“Colors.xml” Contains the colors that we use in our designs
<?xml version="1.0" encoding="utf-8"?> <resources> <color name="primary">#3498DB</color> <color name="primary_pressed">#2C3E50</color> <color name="ripple">#ff80ab</color> <color name="accent">#E64A19</color> <color name="accent_pressed">#BF360C</color> </resources>
“Dimens.xml” Contains the dimensions of our fake header
<?xml version="1.0" encoding="utf-8"?> <resources> <!-- FAKE HEADER HEIGHT --> <dimen name="header_height">230dp</dimen> <!-- Default Action Bar Height Default Android Value--> <dimen name="action_bar_height">56dp</dimen> <!-- Default Toolbar Left Margin Default Android Value--> <dimen name="toolbar_left_margin">72dp</dimen> </resources>
“Style.xml” Contain our Material Design Theme
<?xml version="1.0" encoding="utf-8" ?> <resources> <style name="MyTheme" parent="MyTheme.Base"> </style> <!-- Base theme applied no matter what API --> <style name="MyTheme.Base" parent="Theme.AppCompat.NoActionBar"> <item name="android:windowNoTitle">true</item> <!--We will be using the toolbar so no need to show ActionBar--> <item name="windowActionBar">false</item> <!-- Set theme colors from http://www.google.com/design/spec/style/color.html#color-color-palette--> <!-- colorPrimary is used for the default action bar background --> <item name="colorPrimary">#2196F3</item> <!-- colorPrimaryDark is used for the status bar --> <item name="colorPrimaryDark">#1976D2</item> <!-- colorAccent is used as the default value for colorControlActivated which is used to tint widgets --> <item name="colorAccent">#FF4081</item> <!-- You can also set colorControlNormal, colorControlActivated colorControlHighlight and colorSwitchThumbNormal. --> </style> </resources>
Also we
can add a menu file into our Menu folder “home.xml”
<?xml version="1.0" encoding="utf-8" ?> <menu xmlns:android="http://schemas.android.com/apk/res/android" xmlns:local="http://schemas.android.com/apk/res-auto"> <item android:id="@+id/menu_share" android:icon="@drawable/ic_action_social_share" local:showAsAction="ifRoom" android:title="Share" /> <item android:id="@+id/menu_settings" local:showAsAction="never" android:title="Settings" /> </menu>
Now we continue with the code
First we need to implement “ActionbarActivity” instead
“Activity” in our main activity to keep Android 5 features in old versions also
we set the theme and IOnScrollListener implementation
[Activity (Label = "ExpandibleHeader", MainLauncher = true, Theme = "@style/MyTheme", Icon = "@drawable/icon")] public class MainActivity : ActionBarActivity, AbsListView.IOnScrollListener
Properties/Views
that we need to set up our ListView Header:
// The height of your fully expanded header view (same than in the xml layout) int HeaderHeight { get; set; } int MinHeaderTranslation { get; set; } // Header views View HeaderView { get; set; } TextView HeaderTitle { get; set; } TextView HeaderSubtitle { get; set; } FloatingActionButton HeaderFab { get; set; } Toolbar Toolbar { get; set; } //Main Listview ListView ListView { get; set; }
The logic for the IOnScrollListener gives us all callbacks
when the user scrolls the listview we make all the magic on this part:
#region AbsListView.IOnScrollListener Implementation public void OnScroll (AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { int scrollY = getScrollY(view); // This will collapse the header when scrolling, until its height reaches // the toolbar height HeaderView.TranslationY = Math.Max(0, scrollY + MinHeaderTranslation); // Scroll ratio (0 <= ratio <= 1). // The ratio value is 0 when the header is completely expanded, // 1 when it is completely collapsed float offset = 1 - Math.Max( (float) (-MinHeaderTranslation - scrollY) / -MinHeaderTranslation, 0f); // Update items alpha from offset UpdateItemsAlpha(offset); } public void OnScrollStateChanged (AbsListView view, ScrollState scrollState) { //throw new NotImplementedException (); } void UpdateItemsAlpha(float offset) { // Alpha 255=100%, 0=0% Toolbar.Background.Alpha = (int)((offset)*255); // Alpha 1=100%, 0=0% HeaderFab.Alpha = 1 - offset; HeaderTitle.Alpha = 1 - offset; HeaderSubtitle.Alpha = 1 - offset; } // Method that allows us to get the scroll Y position of the ListView public int getScrollY(AbsListView view) { View c = view.GetChildAt(0); if (c == null) return 0; int firstVisiblePosition = view.FirstVisiblePosition; int top = c.Top; int headerHeight = 0; if (firstVisiblePosition >= 1) headerHeight = this.HeaderHeight; return -top + firstVisiblePosition * c.Height + headerHeight; } #endregion
Activity Menu logic:
/// <Docs>The options menu in which you place your items.</Docs> /// <returns>To be added.</returns> /// <summary> /// This is the menu for the Toolbar/Action Bar to use /// </summary> /// <param name="menu">Menu.</param> public override bool OnCreateOptionsMenu (IMenu menu) { MenuInflater.Inflate (Resource.Menu.home, menu); return base.OnCreateOptionsMenu (menu); } public override bool OnOptionsItemSelected (IMenuItem item) { switch (item.ItemId) { case Resource.Id.menu_share: Intent intent = new Intent(Intent.ActionSend); intent.SetType("text/plain"); intent.PutExtra(Intent.ExtraText, "http://www.alejandroruizvarela.blogspot.com"); intent.PutExtra(Android.Content.Intent.ExtraSubject, "Awesome Material Design example¡¡¡"); StartActivity(Intent.CreateChooser(intent, "Share")); return true; } return base.OnOptionsItemSelected (item); }
After
this now we can set up all our views and properties in the OnCreate Override
method:
protected override void OnCreate (Bundle savedInstanceState) { base.OnCreate (savedInstanceState); // Set our view from the "main" layout resource SetContentView (Resource.Layout.Main); Toolbar = FindViewById<Toolbar>(Resource.Id.toolbar); //Toolbar will now take on default actionbar characteristics SetSupportActionBar (Toolbar); SupportActionBar.Title = "San Juan de los Lagos"; HeaderHeight = Resources.GetDimensionPixelSize(Resource.Dimension.header_height); ListView = FindViewById<ListView> (Resource.Id.listView1); //Create a dummy data var items = new string[] { "San Juan de los Lagos","Lagos de Moreno","Zapopan", "Guadalajara", "Jalostotitlan", "Ajijic", "Cocula","Ciudad Guzmán","La Barca", "Ocotlán", "Puerto Vallarta", "Tepatitlán de Morelos" }; //create a new simple adapter for our main listview var ListAdapter = new ArrayAdapter<String>(this, Android.Resource.Layout.SimpleListItem1, items); ListView.Adapter = ListAdapter; ListView.ItemClick += ListView_ItemClick; // Init the MinHeaderTranslation values MinHeaderTranslation = -HeaderHeight + Resources.GetDimensionPixelOffset(Resource.Dimension.action_bar_height); // Inflate your header view HeaderView = LayoutInflater.Inflate(Resource.Layout.FakeHeader, ListView, false); // Retrieve the header views HeaderTitle = (TextView) HeaderView.FindViewById(Resource.Id.header_title); HeaderTitle.Text = "Downtown"; HeaderSubtitle = (TextView) HeaderView.FindViewById(Resource.Id.header_subtitle); HeaderSubtitle.Text = "Night Life"; HeaderFab = (FloatingActionButton) HeaderView.FindViewById(Resource.Id.header_fab); HeaderFab.ColorNormal = Resources.GetColor(Resource.Color.primary); HeaderFab.ColorPressed = Resources.GetColor(Resource.Color.primary_pressed); HeaderFab.Click += HeaderFab_Click; // Add the headerView to your listView ListView.AddHeaderView(HeaderView, null, false); ListView.SetOnScrollListener (this); } void HeaderFab_Click (object sender, EventArgs e) { Toast.MakeText (this, "Floating Action Button Clicked", ToastLength.Short).Show(); } void ListView_ItemClick (object sender, AdapterView.ItemClickEventArgs e) { //Smooth scroll to the top of listview ListView.SmoothScrollToPosition (0); }
After
this now we can see the result a beautiful Material design header with old
android versions compatibility.
URL References:
http://developer.xamarin.com/samples/android/Support%20v7/
You can
download a full example code from here:
thanks
ResponderEliminar