Upgrade to Pro
— share decks privately, control downloads, hide ads and more …
Speaker Deck
Sign up for free
Menu
Search
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Features
All features
Private URLs
Password Protection
Custom URLS
Scheduled publishing
Remove Branding
Restrict embedding
Deck Collections
Notes
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Explore
Featured decks
Featured speakers
Programming
Technology
Storyboards
Pricing
Search
Sign in
Sign up for free
Canvas al ajillo
Search
Sponsored
·
Your Podcast. Everywhere. Effortlessly.
Share. Educate. Inspire. Entertain. You do you. We'll handle the rest.
→
Adrián Lomas
December 02, 2016
Programming
150
0
Share
Embed
Copy iframe code
Copy JS code
Copy link
Start on current slide
Canvas al ajillo
My expierence with canvas and drawing in Android
Adrián Lomas
December 02, 2016
Other Decks in Programming
See All in Programming
Augmenting AI with the Power of Jakarta EE
ivargrimstad
0
180
TechTown - Creating Composable Callables in Contemporary C++
rollbear
0
130
Railsのためのパスキー実践入門 〜マルチテナントSaaSでの意思決定〜
utakaha
2
540
SalesForceを内製化!? ~ HR事業を支える顧客管理基盤のインフラを大公開 ~
oku053
0
180
Jetpack Compose Mechanisms
skydoves
3
820
UnityでSystem.Net.WebSocketsなWebSocketサーバが動かないのでUnity Monoのコードを覗いてみた / about implementing websocket server with unity mono
drumath2237
1
610
Verilogで学ぶCPU自作入門
uyuki234
8
4.1k
【加筆修正版】Laravel のアプリケーションをどこにデプロイするか #phpcon_ehime
akase244
0
150
KiroのSpecで「五目並べ」を作ってみる
satoshi256kbyte
1
380
[ハンズオン]AIへの指示だけで「五目並べ」を作ってみよう
satoshi256kbyte
1
380
APNsからLive Activityを開始する話
yumnumm
0
170
パズルゲームの作り方 / how to make puzzle games
kaityo256
PRO
2
290
Featured
See All Featured
Typedesign – Prime Four
hannesfritz
42
3.2k
実際に使うSQLの書き方 徹底解説 / pgcon21j-tutorial
soudai
PRO
203
77k
Sharpening the Axe: The Primacy of Toolmaking
bcantrill
46
3k
Leading Effective Engineering Teams in the AI Era
addyosmani
9
2.7k
What the history of the web can teach us about the future of AI
inesmontani
PRO
2
740
Tips & Tricks on How to Get Your First Job In Tech
honzajavorek
1
800
Evolving SEO for Evolving Search Engines
ryanjones
0
330
Design of three-dimensional binary manipulators for pick-and-place task avoiding obstacles (IECON2024)
konakalab
0
620
Navigating Algorithm Shifts & AI Overviews - #SMXNext
aleyda
1
1.7k
10 Git Anti Patterns You Should be Aware of
lemiorhan
PRO
659
62k
Lightning talk: Run Django tests with GitHub Actions
sabderemane
0
300
Why Our Code Smells
bkeepers
PRO
340
58k
Transcript
@glomadrian Adrián García Lomas Canvas al ajillo
Lo que me gustaría que me hubieran contado sobre Canvas
y Custom Views
Los detalles importan Adapta las vistas a las necesidades no
las necesidades a las vistas Un mundo diferente y divertido
Ciclo de vida de una vista
Constructor onAttachedToWindow() onMeassure() onLayout()
dispatchDraw() draw() onDraw() invalidate()
Animación de carga
public Loading(Context context) { super(context); initialize(); } public Loading(Context context,
AttributeSet attrs) { super(context, attrs); initialize(); } public Loading(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initialize(); } private void initialize() { circlePaint = new Paint(); circlePaint.setColor(circleColor); circlePaint.setAntiAlias(true); circlePaint.setStyle(Paint.Style.STROKE); circlePaint.setStrokeWidth(circleStroke); }
¿Qué pasa con el tamaño de la vista?
@Override protected void onSizeChanged(int w, int h, int oldw, int
oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; createCircle(); } private void createCircleArea() { int circleAreawidth = width - strokeWidth; int circleAreaHeight = heihgt - strokeWidth; circleArea = new RectF(strokeWidth, strokeWidth, circleAreawidth, circleAreaHeight); }
onDraw(Canvas canvas) 16ms (60 fps) Evitar nuevas instancias No usar
invalidate()
X Y • width / 2 , height / 2
• 0 , 0
private float circleStartDegree = 0; private float circleEndDegree = 360;
private float actualCircleEndDegree = circleEndDegree; @Override protected void onDraw(Canvas canvas) { drawCircle(canvas); } private void drawCircle(Canvas canvas) { canvas.drawArc(circleArea, circleStartDegree, actualCircleEndDegree, false, circlePaint); }
circlePaint.setPathEffect(new DashPathEffect(new float[]{dashWidth, dashSpace}, 0));
Animación
private void initializeAnimator() { valueAnimator = ValueAnimator.ofInt(circleStartDegree, circleEndDegree); valueAnimator.setDuration(1000); valueAnimator.addUpdateListener(new
ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { int degreeValue = (int) valueAnimator.getAnimatedValue(); actualCircleEndDegree = degreeValue; invalidate(); } }); } private void initialize() { initializePainter(); initializeAnimator(); }
public void start(){ valueAnimator.start(); } ValueAnimator onUpdate degree = value
invalidate onDraw()
Interpolators Acelerate Acelerate Decelerate BounceInterpolator OvershootInterpolator ...
valueAnimator.setInterpolator(new BounceInterpolator());
valueAnimator.setInterpolator(new DecelateInterpolator());
blurPainter = new Paint(circlePaint); blurPainter.setColor(Color.RED); blurPainter.setStrokeWidth(circleStroke * 1.20F); blurPainter.setMaskFilter(new BlurMaskFilter(blurRadius,
BlurMaskFilter.Blur.NORMAL)); private void drawCircle(Canvas canvas) { canvas.drawArc(internalCircle, circleStartDegree, circleEndDegree, false, blurPainter); canvas.drawArc(internalCircle, circleStartDegree, circleEndDegree, false, circlePaint); }
None
setLayerType(LAYER_TYPE_SOFTWARE, null);
Muerte a las vistas cuadradas
@Override protected void onSizeChanged(int w, int h, int oldw, int
oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; createPath(); } private void createPath() { curvedPath = new Path(); curvedPath.moveTo(0, 0); curvedPath.lineTo(width, 0); } @Override protected void onDraw(Canvas canvas) { canvas.drawPath(curvedPath, pathPaint); }
curvedPath.quadTo(x1, y1, x2, y2); x1, y1 x2, y2
private void createPath() { float pathCurvatureY = height / 2;
float middleX = width / 2; curvedPath = new Path(); curvedPath.moveTo(0, 0); curvedPath.quadTo(middleX, pathCurvatureY, width, 0); } 0,0 middleX, pathCurvatureY width, 0
private void createPath() { float pathCurvatureY = height / 2;
float middleX = width / 2; curvedPath = new Path(); curvedPath.moveTo(0, 0); curvedPath.quadTo(middleX, pathCurvatureY, width, 0); curvedPath.lineTo(width, height); } width, height
private void createPath() { float pathCurvatureY = height / 2;
float middleX = width / 2; curvedPath = new Path(); curvedPath.moveTo(0, 0); curvedPath.quadTo(middleX, pathCurvatureY, width, 0); curvedPath.lineTo(width, height); curvedPath.lineTo(0, height); } 0, height
private void createPath() { float pathCurvatureY = height / 2;
float middleX = width / 2; curvedPath = new Path(); curvedPath.moveTo(0, 0); curvedPath.quadTo(middleX, pathCurvatureY, width, 0); curvedPath.lineTo(width, height); curvedPath.lineTo(0, height); curvedPath.close(); }
pathPaint.setStyle(Paint.Style.FILL);
None
None
Interceptando touch events dentro de un área
@Override protected void onSizeChanged(int w, int h, int oldw, int
oldh) { super.onSizeChanged(w, h, oldw, oldh); width = w; height = h; createPath(); createTouchRegion(); } private void createTouchRegion() { RectF pathBoundsRect = new RectF(); curvedPath.computeBounds(rectF, true); regionToCheck = new Region(pathBoundsRect.left, pathBoundsRect.top, pathBoundsRect.right, pathBoundsRect.bottom); regionToCheck.setPath(curvedPath, regionToCheck); }
@Override public boolean onTouchEvent(MotionEvent event) { boolean result = false;
int pointX = (int) event.getX(); int pointY = (int) event.getY(); if (isPointInsidePathArea(pointX, pointY)) { result = super.onTouchEvent(event); } return result; } private boolean isPointInsidePathArea(int x, int y) { return regionToCheck.contains(x, y); }
None
Usando path para animar
private float[] getPathCoordinates(Path path, float fraction) { float aCoordinates[] =
{ 0f, 0f }; PathMeasure pm = new PathMeasure(path, false); pm.getPosTan(pm.getLength() * fraction, aCoordinates, null); return aCoordinates; }
@Override public void onAnimationUpdate(ValueAnimator animation) { float value = animation.getAnimatedFraction();
float[] coordinates = getPathCoordinates(infinitePath, value); this.ballX = coordinates[0]; this.ballY = coordinates[1]; invalidate() }
None
Midiendo el rendimiento
None
None
None
None
onDraw() Recursos OpenGL Espera CPU 16 ms
private void onDraw(Canvas canvas) { heavyWork(); canvas.drawArc(internalCircle, circleStartDegree, circleEndDegree, false,
circlePaint); }
Clean code también en vistas
@Override protected void onDraw(Canvas canvas) { if (mRunning) { if
(mShowLeftEye) { canvas.drawCircle(mLeftEyePos[0], mLeftEyePos[1], mEyeCircleRadius, mCirclePaint); } if (mShowRightEye) { canvas.drawCircle(mRightEyePos[0], mRightEyePos[1], mEyeCircleRadius, mCirclePaint); } if (mFirstStep) { mArcPath.reset(); mArcPath.addArc(mRectF, mStartAngle, mSweepAngle); canvas.drawPath(mArcPath, mArcPaint); } else { mArcPath.reset(); mArcPath.addArc(mRectF, mStartAngle, mSweepAngle); canvas.drawPath(mArcPath, mArcPaint); } } else { canvas.drawCircle(mLeftEyePos[0], mLeftEyePos[1], mEyeCircleRadius, mCirclePaint); canvas.drawCircle(mRightEyePos[0], mRightEyePos[1], mEyeCircleRadius,mCirclePaint); canvas.drawPath(mArcPath, mArcPaint); } }
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); externalCirclePainter.draw(canvas); internalCirclePainter.draw(canvas); progressPainter.draw(canvas);
iconPainter.draw(canvas); }
¿Preguntas?