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

[Said Tahsin Dane] Material Design Custom Views

[Said Tahsin Dane] Material Design Custom Views

Presentation from GDG DevFest Ukraine 2015 - the biggest Google related event in the country. October 23-24, Lviv. Learn more at http://devfest.gdg.org.ua/

Google Developers Group Lviv

October 23, 2015
Tweet

More Decks by Google Developers Group Lviv

Other Decks in Programming

Transcript

  1. #dfua @tasomaniac Android Views What is View? Android SDK has

    some built-in Views TextView, ImageView, Button ViewGroup, LinearLayout, RelativeLayout ViewStub Isn’t the framework good enough?
  2. #dfua @tasomaniac Android Views What are they responsible for? Attachment/Detachment

    Measuring, Drawing Saving UI state Handling Touch Events Listeners/Callbacks
  3. #dfua @tasomaniac Why custom Views? View reuse Unique presentation Custom

    interactions Layout Optimizations Performance Build UIs that are not naturally possible
  4. #dfua @tasomaniac <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <ImageView android:id="@android:id/icon" android:layout_width="wrap_content"

    android:layout_height="wrap_content"/> <TextView android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="8dp"/> </LinearLayout>
  5. #dfua @tasomaniac TextView nameView = (TextView) profileView.findViewById(android.R.id. text1); ImageView iconView

    = (ImageView) profileView.findViewById(android.R.id. icon); nameView.setText(user.getName()) ; iconView.setImageResource(user.getIcon()) ;
  6. #dfua @tasomaniac Ex: ProfileView public class ProfileView extends LinearLayout {

    public ProfileView(Context context) { super(context); } public ProfileView(Context context , AttributeSet attrs) { super(context, attrs); } }
  7. #dfua @tasomaniac public class ProfileView extends LinearLayout { private final

    TextView textView; private final ImageView iconView; private User user; public ProfileView(Context context, AttributeSet attr) { super(context, attr); setOrientation(LinearLayout.HORIZONTAL); setGravity(Gravity.CENTER); inflate(context, R.layout.profile_view, this); textView = (TextView) findViewById(android.R.id.text1); iconView = (ImageView) findViewById(android.R.id.icon); } public void setUser(User user) { this.user = user; textView.setText(user.getName()); iconView.setImageResource(user.getIcon()); } }
  8. #dfua @tasomaniac <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:gravity="center" android:orientation="horizontal"> <ImageView android:id="@android:id/icon" android:layout_width="wrap_content"

    android:layout_height="wrap_content"/> <TextView android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="8dp"/> </LinearLayout> <merge> <ImageView android:id="@android:id/icon" android:layout_width="wrap_content" android:layout_height="wrap_content"/> <TextView android:id="@android:id/text1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginLeft="8dp"/> </merge>
  9. #dfua @tasomaniac public class ProfileView extends LinearLayout implements View.OnClickListener {

    public ProfileView(Context context, AttributeSet attr) { super(context, attr); ... setOnClickListener(this); } ... public void onClick(View v) { if (this.user != null) { Intent i = new Intent(getContext(), ProfileActivity.class); i.putExtra("user", this.user); getContext().startActivity(i); } } }
  10. #dfua @tasomaniac Save State Data model should be separate from

    view state Save user interactions in progress Scroll position Active selections Active modes Uncommitted user input e.g. text entered
  11. #dfua @tasomaniac @Override protected Parcelable onSaveInstanceState() { Bundle bundle =

    new Bundle(); bundle.putParcelable( "user", this.user); return bundle; } @Override protected void onRestoreInstanceState(Parcelable state) { Bundle bundle = (Bundle) state ; this.user = bundle.getParcelable( "user"); } Saving State of your View
  12. #dfua @tasomaniac Material Design! Yey! Use AppCompat to support Material

    Design Ripple Effects Widget Tinting Palette & ColorUtils Theme support
  13. #dfua @tasomaniac Change the theme first! <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <item

    name="colorPrimary">@color/colorPrimary</ item> <item name="colorPrimaryDark">@color/colorPrimaryDark</ item> <item name="colorAccent">@color/colorAccent</ item> </style>
  14. #dfua @tasomaniac Use AppCompatActivity This will automatically use Material Design!

    public class MainActivity extends AppCompatActivity { }
  15. #dfua @tasomaniac Extend your Views from AppCompat alternatives. AppCompatButton AppCompatCheckBox

    AppCompatEditText AppCompatSpinner AppCompatTextView ... In your custom Views
  16. #dfua @tasomaniac Ripple Effect For complicated views with images: <FrameLayout

    android:layout_width="match_parent" android:layout_height="match_parent" android:foreground="?attr/selectableItemBackground"> ………… </FrameLayout>
  17. #dfua @tasomaniac Widget Theming How do you normally achieve this?

    Introduced in Lollipop Available for all thanks to AppCompat
  18. #dfua @tasomaniac Attrs in AppCompat It now contains almost all

    the attrs you may need. ?attr/actionBarSize ?attr/listPreferredItemHeight ?attr/listChoiceBackgroundIndicator or ?android:attr/textColorPrimary
  19. #dfua @tasomaniac Access theme attrs Utility methods to access your

    theme ThemeUtils.getThemeAttrColor(context, R.attr.colorPrimary); Colors and Drawables ContextCompat.getColor(context, R.color.itemBackgroundColor); ContextCompat.getDrawable(context, R.color.itemBackground);
  20. #dfua @tasomaniac Widget Tinting // Wrap the drawable so that

    future tinting calls work // on pre-v21 devices. Always use the returned drawable. drawable = DrawableCompat.wrap(drawable); DrawableCompat.setTint(drawable, Color.RED); // ...or a tint list DrawableCompat.setTintList(drawable, myColorStateList);
  21. #dfua @tasomaniac Palette Palette.Swatch swatch = palette.getVibrantSwatch(); if (swatch !=

    null) { titleView.setBackgroundColor(swatch.getRgb()); titleView.setTextColor(swatch.getTitleTextColor()); }
  22. #dfua @tasomaniac ColorUtils int textColor = Color.WHITE; float minContrastRatio =

    4.5f; // Min contrast ration of 1:4.5 int minAlpha = ColorUtils. calculateMinimumAlpha( textColor, backgroundColor, minContrastRatio); if (minAlpha != -1) { // There is an alpha value which has enough contrast, use it! return ColorUtils.setAlphaComponent(textColor, minAlpha); }