Material Design Custom Views +SaidTahsinDane @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? @tasomaniac @tasomaniac
Android Views What are they responsible for? Attachment/Detachment Measuring, Drawing Saving UI state Handling Touch Events Listeners/Callbacks @tasomaniac @tasomaniac
Why custom Views?
Why custom Views? View reuse Unique presentation Custom interactions Layout Optimizations Performance Build UIs that are not naturally possible @tasomaniac @tasomaniac
ProfileView
@tasomaniac @tasomaniac
@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());
@tasomaniac
Ex: ProfileView public class ProfileView extends LinearLayout { public ProfileView(Context context) { super(context); } public ProfileView(Context context , AttributeSet attrs) { super(context, attrs); } }
@tasomaniac @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()); } } @tasomaniac
android:orientation="horizontal"> @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); } } }
@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 @tasomaniac @tasomaniac
Saving State of your View @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"); }
@tasomaniac @tasomaniac
Material Design
Material Design! Yey! Use AppCompat to support Material Design Ripple Effects Widget Tinting Palette & ColorUtils Theme support
@tasomaniac @tasomaniac
Change the theme first!
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> @color/colorPrimary @color/colorPrimaryDark @color/colorAccent
@tasomaniac @tasomaniac
Use AppCompatActivity
This will automatically use Material Design!
public class MainActivity extends AppCompatActivity { }
@tasomaniac @tasomaniac
In your custom Views Extend your Views from AppCompat alternatives. AppCompatButton AppCompatCheckBox AppCompatEditText AppCompatSpinner AppCompatTextView ...
@tasomaniac @tasomaniac
Ripple Effect How to keep ripples in Custom Views? Be backward compatible
@tasomaniac @tasomaniac
Ripple Effect Use android:background="?attr/selectableItemBackground"
or android:background="?attr/selectableItemBackgroundBorderless"
as your background
@tasomaniac @tasomaniac
Ripple Effect For complicated views with images: …………
@tasomaniac @tasomaniac
Fixes Holo too!
@tasomaniac @tasomaniac
Widget Theming
How do you normally achieve this? Introduced in Lollipop Available for all thanks to AppCompat @tasomaniac @tasomaniac
Widget Theming
@tasomaniac
What about selected states?
Normal behavior
@tasomaniac @tasomaniac
What about selected states?
Find the 3 differences in these images?
@tasomaniac @tasomaniac
Widget Theme’s to the rescue!
@tasomaniac @tasomaniac
Attrs in AppCompat It now contains almost all the attrs you may need. ?attr/actionBarSize ?attr/listPreferredItemHeight ?attr/listChoiceBackgroundIndicator
or ?android:attr/textColorPrimary
@tasomaniac @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);
@tasomaniac
Widget Tinting
First introduced in Lollipop Available backward-compatible with AppCompat.
@tasomaniac @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);
@tasomaniac @tasomaniac
Palette & ColorUtils
Get color palette from your pics Vibrant, Muted Swatch
@tasomaniac @tasomaniac
Palette
Palette.Swatch swatch = palette.getVibrantSwatch(); if (swatch != null) { titleView.setBackgroundColor(swatch.getRgb()); titleView.setTextColor(swatch.getTitleTextColor()); }
@tasomaniac @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); }
@tasomaniac #dfua
Thank you! Questions?
+SaidTahsinDane @tasomaniac