android wear essentials
Post on 11-Jan-2017
104 Views
Preview:
TRANSCRIPT
Android Wear
• Android SDK
• Specific wear APIs in external libraries
(support:wearable, play-services-wearable)
• All devices are compa>ble with API 23
(minSdkVersion 23)
• Only a few devices are compa>ble with API 24
("Android Wear 2.0")
Crea%ng a watch face
1. Create a class that extends CanvasWatchFaceService.Engine
2. Create a Service that extends CanvasWatchFaceService and override onCreateEngine
Prefer OpenGL ES instead of the Canvas API ?Use Gles2WatchFaceService instead
Avoid burn-in
• Do not draw large areas of pixels in ambient mode
• Do not place content within 10 pixels of the edge of the screen
class Engine extends CanvasWatchFaceService.Engine { Paint paint;
@Override void onCreate(SurfaceHolder holder) { paint = new Paint(); paint.setTextSize(80_DIP); paint.setColor(Color.MAGENTA); paint.setStyle(Style.FILL); paint.setTextAlign(Align.CENTER); paint.setAntiAlias(true); }
@Override void onDraw(Canvas canvas, Rect bounds) { canvas.drawText("18:42", bounds.centerX(), bounds.centerY(), paint); }}
Style.STROKE
if (inAmbientMode) { paint.setColor(WHITE); paint.setStyle(STROKE); paint.setStrokeWidth(1_DIP);
if (lowBitEnabled) { paint.setAntiAlias(false); }}
Paint backgroundPaint = new Paint();
@Override void onCreate(SurfaceHolder holder) { super.onCreate(holder);
backgroundPaint.setStyle(FILL); backgroundPaint.setColor(DKGRAY); backgroundPaint.setAntiAlias(true);}
@Override void onDraw(Canvas canvas, Rect bounds) { canvas.drawRect(0, 0, bounds.width(), bounds.height(), backgroundPaint);}
Gradient: Linear / Sweep / Radial
LinearGradient(0, centerY, width, centerY, WHITE, BLACK, CLAMP));SweepGradient(radius, radius, WHITE, BLACK));RadialGradient(centerX, centerY, radius, WHITE, BLACK, CLAMP));
paint.setShader(shader);
Tile mode: Clamp / Mirror / Repeat
tileMode = Shader.TileMode.CLAMP;tileMode = Shader.TileMode.MIRROR;tileMode = Shader.TileMode.REPEAT;
new RadialGradient(radius, radius, radius / 10, WHITE, BLACK, tileMode));
Gradient posi-ons
int[] colors = new int[] { RED, GREEN, BLUE, MAGENTA, CYAN};float[] positions = new float[] { 0f, 0.1f, 0.4f, 0.8f, 1.0f};paint.setShader(new LinearGradient(0, radius, width, radius, colors, positions, CLAMP));
Gradient posi-ons
Shader shader = new LinearGradient( 0, centerY, width, centerY, new int[] {blue, blue, white, white, red, red}, new float[] {0f, 0.33f, 0.33f, 0.66f, 0.66f, 1f}, CLAMP);bgPaint.setShader(shader);
Back to our background
int[] colors = new int[] {DKGRAY, DKGRAY, BLACK, BLACK};float[] positions = new float[] {0, 0.25f, 0.25f, 1f};bgPaint.setShader(new RadialGradient(centerX, centerY, 6_DIP, colors, positions, REPEAT));
Path path;
@Override void onApplyWindowInsets(WindowInsets insets) { [...] path = createMinutesIndicators(centerX, centerY, radius - 10_DP);}
@Override void onDraw(Canvas canvas, Rect bounds) { [...] canvas.drawPath(path, paint);}
Paint handHourPaint;Path handHourPath;
@Override void onCreate(SurfaceHolder holder) { [...] handHourPaint = new Paint(); handHourPaint.setStyle(Paint.Style.FILL); handHourPaint.setColor(Color.WHITE); handHourPaint.setAntiAlias(true); handHourPaint.setPathEffect(new CornerPathEffect(2_DP));}
@Override void onApplyWindowInsets(WindowInsets insets) { [...] handHourPath = createHandHour(centerX, centerY, radius - 20_DP);}
@Override void onDraw(Canvas canvas, Rect bounds) { [...] canvas.drawPath(handHourPath, handHourPaint);}
path.arcTo( new RectF( centerX - 10_DIP, centerY - 10_DIP, centerX + 10_DIP, centerY + 10_DIP ), 180f, -180f);
int[] colors = new int[] { 0xff878191, 0xffaba6b3, 0xffb9b1c5, 0xffa9a2b3};
float[] positions = new float[] { 0, 0.49f, 0.51f, 1f},
Shader gradient = new LinearGradient( radius - 10_DIP, 0, radius + 10_DIP, 0, colors, positions, Shader.TileMode.CLAMP);
handHourPaint.setShader(gradient);
canvas.save();
canvas.rotate( 10 * 360 / 12, centerX, centerY);
canvas.drawPath(path, paint);
canvas.restore();
Paint shadowPaint = new Paint();shadowPaint.setAntiAlias(true);shadowPaint.setColor(GRAY);shadowPaint.setShadowLayer(4f, 4f, 2f, GRAY);[...]canvas.drawPath(handHourPath, shadowPaint);canvas.drawPath(handHourPath, watchHandPaint);
Source codegithub.com/Nilhcem/the-10mn-
watchface
#1: Official documenta2on is !
developer.android.com/wear/index.html
#3: Custom WatchFrame Layouth"ps://github.com/Nilhcem/hexawatch/blob/master/
companion/src/main/java/com/nilhcem/hexawatch/ui/widget/
WearFrameLayout.java
<com.nilhcem.hexawatch.ui.widget.WearFrameLayout android:layout_width="wrap_content" android:layout_height="match_parent">
<com.nilhcem.hexawatch.ui.widget.HexawatchView android:layout_width="match_parent" android:layout_height="match_parent"/></com.nilhcem.hexawatch.ui.widget.WearFrameLayout>
#6: Check out ustwo clockwise SDK
h"ps://github.com/ustwo/clockwise
#7: Stripes shaderaka "A burn-in friendly way to fill a large
surface"
paint.setStyle(Paint.Style.FILL);paint.setShader(new LinearGradient( 0f, 0f, TWO_DIP, TWO_DIP, new int[] { WHITE, WHITE, TRANSPARENT, TRANSPARENT }, new float[] { 0, 0.25f, 0.25f, 1f }, Shader.TileMode.REPEAT ));
#8: Bitmap shadergithub.com/Nilhcem/shammane-
androidwear
Bitmap dotPattern = BitmapFactory.decodeResource( context.getResources(), R.drawable.dot_pattern);
paint.setShader( new BitmapShader( dotPattern, TileMode.REPEAT, TileMode.REPEAT ));
#9: Experiment in an Android (not wear)
custom View
<com.nilhcem.experiments.ui.widget.WearFrameLayout android:layout_width="match_parent" android:layout_height="match_parent">
<com.nilhcem.experiments.ui.ExperimentalView android:layout_width="match_parent" android:layout_height="match_parent"/></com.nilhcem.experiments.ui.widget.WearFrameLayout>
#10: Use ValueAnimator for
onDraw anima7ons
private ValueAnimator animator;private final Handler handler = new Handler();
public void onTapCommand(int tapType, int x, int y, long e) { if (tapType == TAP_TYPE_TAP) { animator = ValueAnimator.ofInt(0, Math.round(MAX_RADIUS)); animator.setDuration(600L); animator.setInterpolator(new AccelerateDecelerateInterpolator()); animator.start(); invalidate(); }}
public void onDraw(Canvas canvas, Rect bounds) { if (animator != null && animator.isRunning()) { int value = (Integer) animator.getAnimatedValue(); canvas.drawCircle(centerX, centerY, value, paint); // Invalidate at a 30fps ratio handler.postDelayed(() -> invalidate()), 1000L / 30); }}
#11: Path Interpolator Anima3on
Path path = new Path(); path.moveTo(0, 0); path.lineTo(0.250f, 0.250f); path.lineTo(0.500f, -0.500f); path.lineTo(0.750f, 0.625f); path.lineTo(0.875f, 0.500f); path.lineTo(1f, 1f);
ObjectAnimator animator = ObjectAnimator.ofFloat(bugdroid, View.TRANSLATION_X, 0, 100); animator.setRepeatCount(ObjectAnimator.INFINITE); animator.setRepeatMode(ObjectAnimator.REVERSE); animator.setInterpolator(PathInterpolatorCompat.create(path)); animator.setDuration(2000); animator.start();
#12: Move a view along a Path
h"p://stackoverflow.com/ques5ons/6154370/android-move-object-along-
a-path
Path path = new Path(); path.arcTo(new RectF(0, 0, 300, 300), 0, 180); // 1 -> 2 path.quadTo(200, 80, 400, 400); // 2 -> 3 path.lineTo(500f, 300f); // 3 -> 4 path.close(); // 4 -> 1
ObjectAnimator animator = ObjectAnimator.ofFloat(bugdroid, "x", "y", path); animator.setRepeatCount(ObjectAnimator.INFINITE); animator.setInterpolator(new DecelerateInterpolator()); animator.setDuration(7000); animator.start();
#13: Port your app to Tizen
• HTML5 Canvas api
• Low-Bit Ambient mode
• Burn-in support
• onTimeTick() becomes window.addEventListener("timetick", drawWatchContent);
Hexawatch
github.com/Nilhcem/hexawatch
• Square / Circular shapes
• Se1ngs app
• Protobuf
• Gear s2 port
• Custom views
• Custom wear frame layout
• Common module
Android Wear Essen-als
• Twi%er: @Nilhcem
• Slides: slideshare.net/Nilhcem/android-wear-essen:als
• Hexawatch: github.com/Nilhcem/hexawatch
• 10mn-watchface: github.com/Nilhcem/the-10mn-watchface
top related