Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Abstract UI Concepts

Abstract UI Concepts

A different way of thinking about writing UI code.

98c2d4d449d87a611778e2ff107f3877?s=128

Sriram Ramani

December 06, 2014
Tweet

Transcript

  1. None
  2. Abstract
 UI Concepts Sriram Ramani sriramramani@fb.com

  3. Giant ListViews

  4. Stories

  5. Stories

  6. Stories

  7. Stories

  8. SHOCK SPOCK A piece of text that extends couple of

    lines. This is the core of the app as this provides the information to the user.
  9. ListView Recycling

  10. ListView Recycling ITEM 1 ITEM 2 ITEM 3 ITEM 4

    ITEM 5 ITEM 6 ITEM 7 ITEM 8 ITEM 8 ITEM 8
  11. ListView Recycling bind the model measure layout addView getView()

  12. ListView Recycling USER NAME A piece of text that extends

    couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME
  13. Break the rows

  14. SHOCK SPOCK A piece of text that extends couple of

    lines. This is the core of the app as this provides the information to the user.
  15. ListView Recycling USER NAME A piece of text that extends

    couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user. USER NAME A piece of text that extends couple of lines. This is the core of the app as this provides the information to the user.
  16. public enum ITEM_TYPES { HEADER, CONTENT, SECONDARY_INFO, FEEDBACK_BAR } @Override

    public int getViewTypeCount() { return ITEM_TYPES.values().length; } @Override public int getItemViewType(int position) { return ITEM_TYPES.values()[position % getViewTypeCount()]; } @Override public View getView(int position, View convertView, ViewGroup parent) { // Bind based on the item type. } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  17. Advantages ▪ Faster binding time ▪ Less time to measure

    ▪ Less time to draw each row ▪ More re-usable rows
  18. Custom ViewGroups

  19. Typical Header

  20. Typical Header Shock Spock 2 hr • San Francisco, CA

  21. LinearLayout of LinearLayouts

  22. LinearLayout weights Shock Spock 2 hr • San Francisco, CA

    Thumbnail LinearLayout (Outer) Title Subtitle Menu LinearLayout (Inner)
  23. LinearLayout weights > LinearLayout (Outer) > Thumbnail > LinearLayout (Inner)

    > Title > Subtitle > Title > Subtitle > Menu > LinearLayout (Inner) > Title > Subtitle Shock Spock 2 hr • San Francisco, CA
  24. RelativeLayout

  25. RelativeLayout Shock Spock 2 hr • San Francisco, CA Title

    Subtitle Thumbnail Menu RelativeLayout
  26. RelativeLayout > RelativeLayout > Menu > Thumbnail > Subtitle >

    Title > Title > Subtitle > Menu > Thumbnail Shock Spock 2 hr • San Francisco, CA
  27. Custom ViewGroup

  28. Custom ViewGroup > CustomViewGroup > Thumbnail > Menu > Title

    > Subtitle Shock Spock 2 hr • San Francisco, CA
  29. @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthConstraints

    = getPaddingLeft() + getPaddingRight(); int heightConstraints = getPaddingTop() + getPaddingBottom(); // Measure the thumbnail. measureChildWithMargins( mThumbnailView, widthMeasureSpec, widthConstraints, heightMeasureSpec, heightConstraints); widthConstraints += mThumbnailView.getMeasuredWidth(); // Measure the title. measureChildWithMargins( mTitleView, widthMeasureSpec, widthConstraints, heightMeasureSpec, heightConstraints); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  30. @Override protected void measureChildWithMargins( View child, int parentWidthMeasureSpec, int widthConstraints,

    int parentHeightMeasureSpec, int heightConstraints) { MarginLayoutParams lp = (MarginLayoutParams) child.getLayoutParams(); int childWidthMeasureSpec = getChildMeasureSpec(parentWidthMeasureSpec, widthConstraints + lp.leftMargin + lp.rightMargin, lp.width); int childHeightMeasureSpec = getChildMeasureSpec(parentHeightMeasureSpec, heightConstraints + lp.topMargin + lp.bottomMargin, lp.height); child.measure(childWidthMeasureSpec, childHeightMeasureSpec); } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
  31. SHOCK SPOCK A piece of text that extends couple of

    lines. This is the core of the app as this provides the information to the user. 1 2 3 4 5
  32. Sub-views

  33. Sub-views LinearLayout ImageView TextView Drawable Layout

  34. TextViews Bacon ipsum dolor sit amet spare ribs pork tongue,

    hamburger biltong rump shoulder turkey ham hock beef tri-tip pork chop jerky fatback.
  35. TextViews Bacon ipsum dolor sit amet spare ribs pork tongue,

    hamburger biltong rump shoulder turkey ham hock beef tri-tip pork chop jerky fatback.
  36. ListView Recycling ITEM 1 ITEM 2 ITEM 3 ITEM 4

    ITEM 5 ITEM 6 ITEM 7 ITEM 8 ITEM 8 ITEM 8
  37. @Override public void setText(CharSequence text) { // Store the text.

    checkForRelayout(); } private void checkForRelayout() { // Make new layout for the new text. makeNewLayout(want, …, width, …); } 1 2 3 4 5 6 7 8 9 10 11 12
  38. Text Layout Caching

  39. public class TextLayoutView extends View { private Layout mLayout; public

    void setText(CharSequence text, String key) { Layout layout = SHARED_LAYOUT_CACHE.get(key); if (layout == null) { // Better to do this in onMeasure() mLayout = new StaticLayout(…); } else { mLayout = layout; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mLayout.draw(canvas); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  40. Advantages ▪ Less object creation ▪ Layout measuring cost is

    saved ▪ Works with Spannables too ▪ Can hack it work for ClickableSpans
  41. Watch out ▪ Orientation change ▪ Locale change ▪ Same

    text in a different context / color
  42. public class TextLayoutView extends View { private Layout mLayout; public

    void setText(CharSequence text, String key) { Layout layout = SHARED_LAYOUT_CACHE.get(key); if (layout == null) { // Better to do this in onMeasure() mLayout = new StaticLayout(…); } else { mLayout = layout; } } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); mLayout.draw(canvas); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  43. PictureDrawable

  44. public class TextLayoutView extends View { private Layout mLayout; private

    Picture mPicture; private boolean mRecorded = false; @Override protected void onDraw(Canvas canvas) { if (!mRecorded) { Canvas pictureCanvas = mPicture.beginRecording( canvas.getWidth(), canvas.getHeight()); super.onDraw(pictureCanvas); mLayout.draw(pictureCanvas); mPicture.endRecording(); mRecorded = true; } mPicture.draw(canvas); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
  45. Sprites

  46. Glyphs

  47. Texture Atlas

  48. Batching & Merging ONE TWO

  49. Batching & Merging ONE TWO

  50. private void drawAPortion() { // Draw the bitmap. canvas.drawBitmap(mBitmap, mSourceRect,

    mDestinationRect, null); } 1 2 3 4 5
  51. public class SpriteImageView extends ImageView { private WeakReference<Bitmap> mBitmap; @Override

    public void onDraw(Canvas canvas) { // Get the destination rectangle. getDrawingRect(mDestinationRect); // Draw the bitmap. canvas.drawBitmap(mBitmap.get(), mSourceRect, mDestinationRect, null); } public void setCoordinates(int left, int top, int width, int height) { mSourceRect.set(left, top, left + width, top + height); invalidate(); } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
  52. Advantages ▪ Pay the cost of reading bitmap once ▪

    Need not be in Android resource cache ▪ Less commands sent to GPU ▪ Same texture re-used
  53. Color Tinting

  54. Glyphs

  55. Tinting COLOR FILTER + =

  56. PorterDuff Mode SRC_OVER

  57. PorterDuff Mode DST_OVER

  58. PorterDuff Mode SRC_IN

  59. PorterDuff Mode SRC_IN

  60. private void tintGlyph(int tintColor) { // Create a color filter.

    ColorFilter colorFilter = new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN); // Set it on the drawable. mDrawable.setColorFilter(colorFilter); } 1 2 3 4 5 6 7 8 9
  61. State Changes

  62. <selector> <!— Selected —> <item android:state_selected=“true” android:state_enabled=“true” android:color=“@color/blue” /> <!—

    Enabled —> <item android:state_enabled=“true” android:color=“@color/white” /> <!— Disabled —> <item android:color=“@color/grey” /> </selector> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
  63. public class TintImageView extends ImageView { private ColorStateList mTintColor; @Override

    protected void drawableStateChanged() { super.drawableStateChanged(); if (mTintColor != null) { // Get the color for the state. int[] state = getDrawableState(); int tintColor = mTintColor.getColorForState(state, 0); // Create a color filter. ColorFilter colorFilter = new PorterDuffColorFilter(tintColor, PorterDuff.Mode.SRC_IN); // Set it on the image. setColorFilter(colorFilter); } } } 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22
  64. Advantages ▪ Cuts down resources in half (or even more)

    ▪ Can be combined with sprites ▪ Only one bitmap is loaded even for StateListDrawable
  65. That’s all folks!