Upload
lars-vogel
View
1.451
Download
9
Embed Size (px)
Citation preview
Android UI-Design and customer views
Lars Vogel
Eclipse IDE and platform developer
Android and Eclipse developer and trainer
Founder of vogella GmbH
http://www.vogella.comvisited by > 50 000 developers every day
Select
ed des
ign pr
incipl
es
How to
imple
ment t
hem (w
ith fo
cus on
custom
views
)
Android design homepage
Android design principles
Never lose my stuff
Decide for me but let me have the final say
Only show what I need when I need it
Delight me in surprising ways
Give me tricks that work everywhere
Lets implements that!
Design principles implemented
Never lose my stuff
Decide for me but let me have the final say
http://www.vogella.com/tutorials/AndroidListView/article.html#listview_undoaction
FrameLayout
Never loose my stuf
Only show what I need when I need it
Design principles implemented
Only show what I need when I need it
http://www.vogella.com/tutorials/AndroidActionBar/article.html
Example Navigation
Home screen Six Pack
Fixed tabs
Spinner
The winner: Navigation Drawer
Implementation of Navigation drawer
Implementation
mDrawerToggle = new ActionBarDrawerToggle(this, /* host Activity */ mDrawerLayout, /* DrawerLayout object */ R.drawable.ic_drawer, /* nav drawer icon to replace 'Up' caret */ R.string.drawer_open, /* "open drawer" description */ R.string.drawer_close /* "close drawer" description */) { /** Called when a drawer has settled in a completely closed state. */ public void onDrawerClosed(View view) { getActionBar().setTitle(title); } /** Called when a drawer has settled in a completely open state. */ public void onDrawerOpened(View drawerView) { getActionBar().setTitle("Open Drawer"); } }; // Set the drawer toggle as the DrawerListener mDrawerLayout.setDrawerListener(mDrawerToggle);
getActionBar().setDisplayHomeAsUpEnabled(true); getActionBar().setHomeButtonEnabled(true);
Management does
not allow me to use the support library
Navigation draweris old school
FrameLayout
Design principles implemented
Delight me in surprising ways
Animations
http://www.vogella.com/tutorials/AndroidAnimations/article.html
Animation history
Properties API (3.0)
New simplified options for Animations (4.1)
ActivityOptions for Activity animations (4.1)
Scenes and transitions (4.4)
NineOldAndroids to support < 3.0 Android versions
aniView.animate().rotation(dest).setDuration(1000).scaleX(2).scaleY(2).withEndAction(new Runnable() {
@Overridepublic void run() {//aniView.animate().rotationXBy(100).rotation(Math.abs(360 - aniView.getRotation())).scaleX(0.4F).scaleY(0.4F).setDuration(1000);}
});
Animations example
Scene animations with Android 4.4
mSceneRoot = (ViewGroup) findViewById(R.id.sceneRoot);
TransitionInflater inflater = TransitionInflater.from(this);
mScene1 = Scene.getSceneForLayout(mSceneRoot, R.layout.transition_scene1, this);
mTransitionManager.transitionTo(mScene1);
Animations
http://graphics-geek.blogspot.de/2013/06/devbytes-custom-activity-animations.html
Demo from Android developer team: com.vogella.android.animations.extended
Design principles implemented
Delight me in surprising ways
http://www.vogella.com/tutorials/AndroidCustomViews/article.html
Custom views
Custom views a can be performance optimized, simplify your developer life or do something awesome
Why?
View drawing phases
Animate Measure Layout Draws
requestLayout() invalidate()animate()
View hierarchy
View
ImageView TextView ViewGroup
Button
LinearLayout FrameLayout ...
View class
It is the basic build block for UI
Rectangular area responsible for drawing and event handling
Creating a custom view
Compound view
Extending an existing view
Custom view
Compound Views
Uses layout with existing views
Adds view interaction and API
Compound View - Layout<?xml version="1.0" encoding="utf-8"?><merge xmlns:android="http://schemas.android.com/apk/res/android" >
<TextView android:layout_width="0dp" android:layout_height="wrap_content" android:layout_weight="1" android:layout_centerVertical="true" android:layout_marginLeft="16dp" android:textSize="18sp" />
<View android:layout_width="26dp" android:layout_height="26dp" android:layout_centerVertical="true" android:layout_marginLeft="16dp" android:layout_marginRight="16dp" />
</merge>
Custom attributes
<?xml version="1.0" encoding="utf-8"?><resources> <declare-styleable name="ColorOptionsView"> <attr name="titleText" format="string"
localization="suggested" /> <attr name="valueColor" format="color" /> </declare-styleable>
</resources>
public class ColorOptionsView extends LinearLayout {
private View mValue;private ImageView mImage;
public ColorOptionsView(Context context, AttributeSet attrs) {super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ColorOptionsView, 0, 0);String titleText = a.getString(R.styleable.ColorOptionsView_titleText);int valueColor = a.getColor(R.styleable.ColorOptionsView_valueColor,android.R.color.holo_blue_light);a.recycle();
setOrientation(LinearLayout.HORIZONTAL);setGravity(Gravity.CENTER_VERTICAL);
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);inflater.inflate(R.layout.view_color_options, this, true);
TextView title = (TextView) getChildAt(0);title.setText(titleText);
mValue = getChildAt(1);mValue.setBackgroundColor(valueColor);
}
public ColorOptionsView(Context context) {this(context, null);}
public void setValueColor(int color) {mValue.setBackgroundColor(color);}
public void setImageVisible(boolean visible) {mImage.setVisibility(visible ? View.VISIBLE : View.GONE);}
}
Get layout parameters
Additional API
Inflate layout, wire views
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:custom="http://schemas.android.com/apk/res/com.vogella.android.view.compoundview" android:layout_width="match_parent" android:layout_height="match_parent" android:divider="?android:attr/listDivider" android:orientation="vertical" android:showDividers="middle" tools:context=".MainActivity" >
<com.vogella.android.customview.compoundview.ColorOptionsView android:id="@+id/view1" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:background="?android:selectableItemBackground" android:onClick="onClicked" custom:titleText="Background color" custom:valueColor="@android:color/holo_green_light" />
<com.vogella.android.customview.compoundview.ColorOptionsView android:id="@+id/view2" android:layout_width="match_parent" android:layout_height="?android:attr/listPreferredItemHeight" android:background="?android:selectableItemBackground" android:onClick="onClicked" custom:titleText="Foreground color" custom:valueColor="@android:color/holo_orange_dark" />
</LinearLayout>
Performance optimizationCreating something completely new
What can I NOT do with compound views?
Performance Flat Custom View
Custom View
Extend View class or its subclass
Override some methodsonDraw()onTouchEvent()…
Use new class in your layout
Canvas API
You draw on a surface creating a Bitmap
Canvas provides API to draw on the canvas
Note: As of Android 4.0, the runtime maps the Canvas API to OpenGL calls
Paint
paint.setColor(Color.WHITE);paint.setStyle(Paint.Style.STROKE);paint.setStrokeJoin(Paint.Join.ROUND);paint.setStrokeWidth(10f);paint.setAlpha(122);
Shader
Define content drawn be Paint
BitmapShaderLinearGradientRadialGradientSweepGradient
Extend an existing layout
MyShinyLinearLayout extends LinearLayout
public MyShinyLinearLayout(Context context, AttributeSet attrs) { super(context, attrs); setBackgroundResource(R.drawable.background);}
private void createShineArea() {int width = getWidth();int height = (int) (0.9 * getHeight());path = new Path();path.moveTo(0, 0);path.lineTo(width, 0);path.lineTo(width, height);path.close();paint.setShader(new LinearGradient(0, 0, 0, height,
0x55ffffff, 0x10ffffff, Shader.TileMode.CLAMP));
}
@Overrideprotected void dispatchDraw(Canvas canvas) {
if (path == null) { createShineArea();
}
// Draw the shine behind the children.canvas.drawPath(path, paint);// Draw the childrensuper.dispatchDraw(canvas);
}
@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {
super.onLayout(changed, l, t, r, b);// Invalidate the path whenever the size changes.path = null;
}
Alpha Compositioin
Matrix
@Overrideprotected void onDraw(Canvas canvas) {
Bitmap targetBitmap = BitmapFactory.decodeResource(getResources(),R.drawable.ic_launcher);Matrix matrix = new Matrix();matrix.setRotate(50, targetBitmap.getWidth() / 2,targetBitmap.getHeight() / 2);matrix.setSkew(2, 2);canvas.drawBitmap(targetBitmap, matrix, new Paint());super.onDraw(canvas);
}
Demo:Custom drawing & touch
View Persistence
View State
To save a view state, Activity calls onSaveInstanceState() on every its child view which has an android:id attribute.
To restore a view state, Activity calls onRestoreInstanceState() on every its child view which has an android:id attribute.
com.vogella.android.customview.persistence
Async custom view
See http://lucasr.org/2014/05/12/custom-layouts-on-android/
Thats about it, but real implementations look a bit more complex
Give me tricks that work everywhere
Design principle
Give me tricks that work everywhere
Implement Fling with Touch
Awesome code examples
SwipeToDismiss - https://github.com/romannurik/Android-SwipeToDismiss
ListView3D - https://github.com/renard314/ListView3d
Rounded Corners with custom drawables - http://www.curious-creature.org/2012/12/11/android-recipe-1-image-with-rounded-corners/
Spotlight - http://www.curious-creature.org/2012/12/13/android-recipe-2-fun-with-shaders/
Path traces http://www.curious-creature.org/2013/12/21/android-recipe-4-path-tracing/
Idea to develop an async custom view
See http://lucasr.org/2014/05/12/custom-layouts-on-android/
Note: Learn about Drawables
http://www.vogella.com/tutorials/AndroidDrawables/article.html
Sometimes you don't need custom views just a combination of existing Drawables