Dmytro Danylyk
Timee GmbH.
<style name="Base.TextAppearance.AppCompat.Body1">
<item name="android:textSize">@dimen/abc_text_size_body_1_material</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
<style name="Base.TextAppearance.AppCompat.Caption">
<item name="android:textSize">@dimen/abc_text_size_caption_material</item>
<item name="android:textColor">?android:textColorSecondary</item>
</style>
...
<style name="Base.TextAppearance.AppCompat.Button">
<item name="android:textSize">@dimen/abc_text_size_button_material</item>
<item name="textAllCaps">true</item>
<item name="android:textColor">?android:textColorPrimary</item>
</style>
Material text styles and dimensions are available in appcompat-v7 library.
styles_base_text.xml
Lollipop
Older versions
<?xml version="1.0" encoding="utf-8"?>
<ripple android:color="@color/flat_pressed">
<item
android:id="@android:id/mask"
android:drawable="@drawable/btn_flat_normal"/>
</ripple>
Android L - Ripple effect
res/drawable-v21
<?xml version="1.0" encoding="utf-8"?>
<selector
android:exitFadeDuration="400"
android:enterFadeDuration="400">
<item android:drawable="@drawable/btn_flat_pressed"
android:state_pressed="true" />
<item android:drawable="@android:color/transparent" />
</selector>
Older versions - Fade selector
res/drawable
Wrap view with a CardView and set app:cardElevation attribute.
CardView can't draw circle shadow.
Not possible to set shadow position.
2.
1.
Not possible to set shadow color. (Make shadow darker or lighter)
3.
No method to set selector for shadow. (Lift on touch)
4.
Set background 9.png image.
For every component you need shadow image for all drawable-dpi folders.
1.
Ton's of resources increase apk size.
2.
Not flexible for changes.
3.
app:sl_shadowRadius="4dp"
app:sl_dy="0dp"
app:sl_dx="0dp"
app:sl_shadowRadius="8dp"
app:sl_dy="4dp"
app:sl_dx="0dp"
<com.dd.ShadowLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:sl_shadowColor="#AA000000"
app:sl_cornerRadius="4dp"
app:sl_dy="1dp"
app:sl_dx="1dp"
app:sl_shadowRadius="4dp">
<!--Your view here-->
</com.dd.ShadowLayout>
Custom view group which will wrap View and display shadow for pre Lollipop devices.
res/layout
setShadowLayer(float radius, float dx, float dy, int shadowColor)
Approach 1: draw shadow on generated Bitmap with shadow layer.
1.
Simple ~ 100 lines of code.
3.
Not very efficient.
4.
Approach 2: draw shadow on view canvas. (without hardware acceleration)
2.
Lollipop
Older versions
<style name="AppCompat.Button.Flat" parent="Base.TextAppearance.AppCompat">
<item name="android:background">@drawable/btn_flat_selector</item>
<item name="android:minWidth">88dp</item>
<item name="android:minHeight">36dp</item>
<item name="android:textAllCaps">true</item>
<item name="android:textSize">14sp</item>
<item name="android:textStyle">bold</item>
...
</style>
res/values/styles.xml
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
style="@style/AppCompat.Button.Flat"/>
res/layout
Button with custom style and transparent background selector.
Lollipop
Older versions
<android.support.v7.widget.CardView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:cardCornerRadius="4dp"
app:cardPreventCornerOverlap="false"
app:cardElevation="2dp">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:minWidth="88dp"
android:minHeight="36dp"
android:text="Button"
...
/>
</android.support.v7.widget.CardView>
Button wrapped with a CardView and cardElevation.
res/layout
Lollipop
Older versions
<com.dd.ShadowLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:shadowColor="#AA000000"
app:cornerRadius="56dp"
app:dy="1dp"
app:shadowRadius="4dp">
<ImageButton
android:layout_width="56dp"
android:layout_height="56dp"
android:layout_gravity="center"
android:src="@drawable/ic_add_white"
android:background="@drawable/selector"
android:elevation="4dp"/>
</com.dd.ShadowLayout>
ImageButton with icon and oval shape as a background, wrapped with ShadowLayout to display shadow for pre Lollipop devices.
res/layout
Why not to use CardView for shadow?
1.
You can't make card view circle.
Why not to use png image for shadow?
2.
Different buttons have different size, shadow radius, position, color - creating separate set of resources is not convenient - but most efficient.
(in progress)
(in progress)
(in progress)
(in progress)
<com.dd.ErrorLabelLayout
android:id="@+id/nameErrorLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/editFirsName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="First name"/>
</com.dd.ErrorLabelLayout>
Custom view group which will wrap EditText, show error label and tint EditText background to red or any other color.
res/layout
mEditText.getBackground().setColorFilter(mErrorColor, PorterDuff.Mode.SRC_ATOP);
To tint EditText drawable you can use ColorFilter.
public void setError(String text) {
mErrorLabel.setVisibility(VISIBLE);
mErrorLabel.setText(text);
// tint drawable
mDrawable.setColorFilter(mErrorColor, PorterDuff.Mode.SRC_ATOP);
// changing focus from EditText to error label, necessary for Android L only
// EditText background Drawable is not tinted, until EditText remains focus
mErrorLabel.requestFocus();
}
EditText background Drawable is not tinted, until EditText remains focus, don't forget to switch focus to other view.
2.
1.
Keep it simple ~ 100 lines of code
3.
<com.dd.FloatLabelLayout
android:id="@+id/nameFloatLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:id="@+id/editFirsName"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="First name"/>
</com.dd.FloatLabelLayout>
Custom view group which will wrap EditText, show floating label when EditText is in focus.
res/layout
MaterialDialog.Builder build = new MaterialDialog.Builder(this)
.body(...)
.title(...)
.buttonMode(MaterialDialog.ButtonMode.NORMAL)
.positiveButton("Agree",
new MaterialDialog.ButtonClickListener() {
@Override
public void onButtonClicked(MaterialDialog dialog, View view) {
dialog.dismiss();
}
})
.negativeButton("Disagree",
new MaterialDialog.ButtonClickListener() {
@Override
public void onButtonClicked(MaterialDialog dialog, View view) {
dialog.dismiss();
}
});
MaterialDialog materialDialog = build.build();
materialDialog.show();
Extend Dialog and set custom content view. As a root layout use either CardView or ShadowLayout.
As a root view preferable to use ShadowLayout which gives you darker shadow in comparison with CardView.
getWindow().setDimAmount(0.4f);
Material dialog use lighter dim amount value.
2.
1.
For buttons use AppCompat.Button.Flat style (see Flat button section).
3.
For text style use TextAppearance.AppCompat.Body1 and TextAppearance.AppCompat.Title from appcompat-v7 library.
4.
(in progress)
(in progress)
Snackbar.Builder builder = new Snackbar.Builder(this)
.timeout(Snackbar.TIMEOUT_MEDIUM)
.type(Snackbar.Type.SNACKBAR)
.title(...)
.buttonColor(Color.BLUE)
.button("Undo", new Snackbar.ButtonClickListener() {
@Override
public void onButtonClicked(Snackbar snackbar, View view) {
snackbar.cancel();
}
});
Snackbar snackbar = builder.create();
snackbar.show();
Create class which will add or remove Snackbar's view to activity decor view over all other components.
To show snackbar use activity decor view group.
activity.getWindow().getDecorView();
1.
For buttons use AppCompat.Button.Flat style (see Flat button section).
2.
For text style use TextAppearance.AppCompat.Body1 from appcompat-v7 library.
3.
(in progress)
(in progress)
DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(this,
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH));
datePickerDialog.setYearRange(1985, 2015);
datePickerDialog.show(getFragmentManager(), null);
TimePickerDialog timePickerDialog = TimePickerDialog.newInstance(this,
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE), true);
timePickerDialog.show(getFragmentManager(), null);
Clone and add as a library project.
https://android.googlesource.com/platform/frameworks/opt/datetimepicker
Use CardView or ShadowLayout if you need shadow for pre Lollipop.
Almost all third party libraries have issues and only partly imitates Material Design spec behavior.
1.
2.
Some components are easy to implement - it is worth it to make your own material-support library and reuse it.
3.