We will explore how Android (especially in recent versions) lets you develop awesomer apps and how you can tap into that potential with Xamarin.Android. Topics covered will include graphics, user interaction, best practices and animations.
Jérémie LavalHappy HackerXamarin[email protected]Tips & Tricks to Spice UpYour Android App
View Slide
Spice-Up Tricks
ListView Tricks
Why ListView? Ubiquity.
From Basic ListView…Boring
… to Complete App
Let’s Build This
Breaking Things Up1. The BasicsLoading and data fetching2. The PrettyImproving the look and feel3. The GimmickSpicing up the result
The Basics
DEMO
ListFragment Customization
01020304050607080910111213141516ListFragment Customization android:orientation="vertical" android:layout_width="fill_parent" android:layout_height="fill_parent"> android:orientation="horizontal" android:id="@id/android:empty"> android:id="@id/android:list" android:layout_weight="1" />
...LulzDogLulzCat......Warning! Async Loadingrequestcallback
0102030405060708091011121314Async Loadingpublic override View GetView (int position, View convertView, ViewGroup parent){ MyCustomView view = EnsureView (convertView); var versionNumber = Interlocked.Increment (ref view.VersionNumber); var item = events [position]; var avatarView = view.FindViewById (...); avatarView.SetImageDrawable (EmptyAvatarDrawable); FetchAvatar (view, avatarView, item, versionNumber); return view;}
010203040506070809101112131415Async Loading (cont)var imageCache = new ConcurrentDictionary> ();void FetchAvatar (... view, ... avatarView, string url, long versionNumber){ var bmp = imageCache.GetOrAdd (url, u => Task.Run (() => DownloadData (u))); if (bmp.IsCompleted && bmp.Result != null) avatarView.SetImage (bmp.Result); else bmp.ContinueWith (t => { if (view.VersionNumber == versionNumber && t.Result != null) handler.Post (() => { if (view.VersionNumber == versionNumber) avatarView.SetImageAnimated (t.Result); }); });}
The Pretty
010203040506070809101112131415Prettify Your List Items android:shape="rectangle"> android:startColor="@android:color/transparent" android:endColor="#10000000" android:type="linear" android:centerColor="@android:color/transparent" android:centerY="0.8" android:angle="270" /> android:width="1dp" android:color="#D0D0D0" />
Prettify Your List Items
010203040506070809101112131415Custom Drawablepublic class RoundCornersDrawable : Drawable{ public RoundCornersDrawable (Bitmap bitmap, float cornerRadius = 5) { this.cornerRadius = cornerRadius; this.paint = new Paint () { AntiAlias = true }; var tileMode = Shader.TileMode.Clamp; paint.SetShader (new BitmapShader (bitmap, tileMode, tileMode)); } public override void Draw (Canvas canvas) { canvas.DrawRoundRect (rect, cornerRadius, cornerRadius, paint); }}
Custom DrawableimageView.SetImageDrawable (new RoundCornersDrawable (glacierBmp, cornerRadius: 10))
01020304050607080910111213141516Easy Inset Effects android:text="White-‐based inset" android:shadowColor="@android:color/white" android:shadowDx="1" android:shadowDy="1" android:shadowRadius="0.1" /> android:text="Black-‐based inset" android:shadowColor="@android:color/black" android:shadowDx="-‐1" android:shadowDy="-‐1" android:shadowRadius="0.1" />
Easy Inset Effects
The Gimmick
The Animated Stuff
“The best animations are the ones your usersdon’t notice because they feel natural”
- Jérémie Laval“The best animations are the ones your usersdon’t notice because they feel natural”
0102030405060708091011121314Fade ImageViewpublic static class ImageViewExtensions{ public static void SetImageDrawableAnimated (this ImageView view, Drawable drawable) { var lng = view.Resources.GetInteger (ConfigLongAnimTime); var med = view.Resources.GetInteger (ConfigMediumAnimTime); view.Animate ().Alpha (0).SetDuration (med).WithEndAction (() => { view.SetImageDrawable (drawable); view.Animate ().Alpha (1).SetDuration (lng); }); }}
01020304050607080910111213ListView Item Animationspublic override View GetView (int position, View convertView, ViewGroup parent){ var view = EnsureView (convertView); var item = events [position]; if (!item.Consumed) { item.Consumed = true; var animation = AnimationUtils.MakeInChildBottomAnimation (context); view.StartAnimation (animation); } return view;}
01020304050607080910111213Automatic Layout Transitions android:orientation="vertical" android:id="@+id/AnimatedLayout" android:animateLayoutChanges="true" android:minHeight="49dp" android:layout_height="wrap_content"> android:layout_height="1px" />
0102030405060708091011121314Automatic Layout Transitionsif (presentationLayout.Visibility == ViewStates.Gone) { presentationLayout.Visibility = ViewStates.Visible; var lp = new LayoutParams (actionLayout.LayoutParameters) { Height = 1 }; actionLayout.LayoutParameters = lp;} else { var lp = new LayoutParams (actionLayout.LayoutParameters) { Height = ViewGroup.LayoutParams.WrapContent, Gravity = GravityFlags.Center }; actionLayout.LayoutParameters = lp; presentationLayout.Visibility = ViewStates.Gone;}
Last Call
developers.android.com/designA worthy read for every app developer
Thanks!/garuma/EvolveDemo