Created
December 3, 2012 13:26
-
-
Save roman-mazur/4195038 to your computer and use it in GitHub Desktop.
Code examples used at "Fine-tuning Android apps" talk: http://goo.gl/1fV7T
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.graphics.Canvas; | |
import android.graphics.Color; | |
import android.graphics.ColorFilter; | |
import android.graphics.LinearGradient; | |
import android.graphics.Paint; | |
import android.graphics.Path; | |
import android.graphics.Rect; | |
import android.graphics.Shader; | |
import android.graphics.Shader.TileMode; | |
import android.graphics.drawable.Drawable; | |
public class AnimatedCrossDrawable extends Drawable { | |
static final int MAX_LEVEL = 100000; | |
private final Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG), gradientPaint = new Paint(Paint.ANTI_ALIAS_FLAG); | |
private final Path clipPath = new Path(); | |
private Shader gradient; | |
{ | |
paint.setColor(Color.BLUE); | |
} | |
private final FpsTracker fpsTracker = new FpsTracker("DrawableFps"); | |
@Override | |
protected boolean onLevelChange(int level) { | |
super.onLevelChange(level); | |
invalidateSelf(); | |
return true; | |
} | |
@Override | |
protected void onBoundsChange(Rect bounds) { | |
super.onBoundsChange(bounds); | |
gradient = new LinearGradient(bounds.left, bounds.top, bounds.right, bounds.top, Color.BLUE, Color.YELLOW, TileMode.CLAMP); | |
gradientPaint.setShader(gradient); | |
} | |
@Override | |
public void draw(final Canvas canvas) { | |
fpsTracker.trackFps(); | |
Rect bounds = getBounds(); | |
float part = (float)getLevel() / MAX_LEVEL; | |
float x = bounds.left + part * bounds.width(); | |
float y = bounds.top + part * bounds.height(); | |
canvas.drawLine(0f, 0f, x, y, paint); | |
canvas.drawLine(0f, bounds.bottom, x, bounds.bottom - y, paint); | |
float centerX = bounds.exactCenterX(), centerY = bounds.exactCenterY(); | |
Path clipPath = this.clipPath; | |
clipPath.rewind(); | |
clipPath.moveTo(0, 0); | |
clipPath.lineTo(Math.min(x, centerX), Math.min(y, centerY)); | |
clipPath.lineTo(Math.min(x, centerX), Math.max(bounds.bottom - y, centerY)); | |
clipPath.lineTo(0, bounds.bottom); | |
clipPath.lineTo(0, 0); | |
if (x > centerX) { | |
clipPath.moveTo(centerX, centerY); | |
clipPath.lineTo(x, bounds.bottom - y); | |
clipPath.lineTo(x, y); | |
clipPath.lineTo(centerX, centerY); | |
} | |
canvas.clipPath(clipPath); | |
canvas.drawRect(bounds, gradientPaint); | |
} | |
@Override | |
public void setAlpha(final int alpha) { } | |
@Override | |
public void setColorFilter(final ColorFilter cf) { } | |
@Override | |
public int getOpacity() { return 0; } | |
@Override | |
public int getIntrinsicHeight() { return 0; } | |
@Override | |
public int getIntrinsicWidth() { return 0; } | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.app.Activity; | |
import android.os.Bundle; | |
import android.view.View; | |
public class AnimationActivity extends Activity { | |
public static float line(float x1, float y1, float x2, float y2, float x) { | |
return (x - x1) / (x2 - x1) * (y2 - y1) + y1; | |
} | |
public static float interpolate(final float fraction) { | |
final float[] x = {0f, 0.2f, 0.4f, 0.6f, 0.8f, 1f}; | |
final float[] y = {0f, 0.2f, 0.1f, 0.6f, 0.5f, 1f}; | |
for (int i = 0; i < x.length; i++) { | |
if (fraction < x[i]) { | |
return line(x[i - 1], y[i - 1], x[i], y[i], fraction); | |
} | |
} | |
return fraction; | |
} | |
@SuppressWarnings("deprecation") | |
@Override | |
public void onCreate(final Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
final View view = new View(this); | |
final AnimatedCrossDrawable animDrawable = new AnimatedCrossDrawable(); | |
view.setBackgroundDrawable(animDrawable); | |
setContentView(view); | |
new LevelAnimator(animDrawable) { | |
@Override | |
protected float interpolate(final float fraction) { | |
return AnimationActivity.interpolate(fraction); | |
} | |
} | |
.setDuration(4000) | |
.start(0, AnimatedCrossDrawable.MAX_LEVEL); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.animation.TimeInterpolator; | |
import android.annotation.TargetApi; | |
import android.app.Activity; | |
import android.graphics.Color; | |
import android.os.Build; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.view.ViewTreeObserver.OnPreDrawListener; | |
import android.widget.FrameLayout; | |
import android.widget.FrameLayout.LayoutParams; | |
@TargetApi(Build.VERSION_CODES.ICE_CREAM_SANDWICH) | |
public class AnimationActivity2Views extends Activity { | |
@SuppressWarnings("deprecation") | |
@Override | |
public void onCreate(final Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
FrameLayout layout = new FrameLayout(this); | |
layout.setBackgroundColor(Color.WHITE); | |
final View view = new View(this); | |
final AnimatedCrossDrawable animDrawable = new AnimatedCrossDrawable(); | |
view.setBackgroundDrawable(animDrawable); | |
animDrawable.setLevel(AnimatedCrossDrawable.MAX_LEVEL); | |
view.setLayerType(View.LAYER_TYPE_SOFTWARE, null); | |
layout.addView(view, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); | |
View top = new View(this); | |
top.setBackgroundColor(Color.WHITE); | |
layout.addView(top, LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); | |
setContentView(layout); | |
//top.setLayerType(View.LAYER_TYPE_HARDWARE, null); | |
top.animate() | |
.translationX(getResources().getDisplayMetrics().widthPixels) | |
.setInterpolator(new TimeInterpolator() { | |
public float getInterpolation(float input) { | |
return AnimationActivity.interpolate(input); | |
} | |
}) | |
.setDuration(4000); | |
// FPS... | |
final FpsTracker tracker = new FpsTracker("HWTracker"); | |
top.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { | |
public boolean onPreDraw() { | |
tracker.trackFps(); | |
return true; | |
} | |
}); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.app.ListActivity; | |
import android.graphics.Typeface; | |
import android.os.Bundle; | |
import android.view.View; | |
import android.view.ViewGroup; | |
import android.widget.BaseAdapter; | |
import android.widget.TextView; | |
public class BAD_FontsActivity extends ListActivity { | |
@Override | |
protected void onCreate(Bundle savedInstanceState) { | |
super.onCreate(savedInstanceState); | |
setListAdapter(new TestFontsAdapter()); | |
} | |
public class TestFontsAdapter extends BaseAdapter { | |
public int getCount() { | |
return Integer.MAX_VALUE; | |
} | |
public Object getItem(int position) { | |
return null; | |
} | |
public long getItemId(int position) { | |
return position; | |
} | |
public View getView(int position, View convertView, ViewGroup parent) { | |
TextView textView; | |
if (convertView == null) { | |
textView = new TextView(BAD_FontsActivity.this); | |
} else { | |
textView = (TextView) convertView; | |
} | |
textView.setText(String.valueOf(position)); | |
textView.setTypeface(Typeface.createFromAsset(getAssets(), "Roboto-Light.ttf")); | |
return textView; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.os.SystemClock; | |
import android.util.Log; | |
public final class FpsTracker { | |
private long lastFpsTrackedTime, startTime, prevCallTime; | |
private int framesCount = 0, totalCount = 0; | |
private final String tag; | |
public FpsTracker(final String tag) { | |
this.tag = tag; | |
} | |
public void trackFps() { | |
long now = SystemClock.uptimeMillis(); | |
totalCount++; | |
framesCount++; | |
if (lastFpsTrackedTime == 0) { | |
startTime = now; | |
lastFpsTrackedTime = now; | |
prevCallTime = now; | |
return; | |
} | |
long frameTime = now - prevCallTime; | |
prevCallTime = now; | |
Log.i(tag, "Frame time: " + frameTime); | |
long fpsTime = now - lastFpsTrackedTime; | |
if (fpsTime >= 1000) { | |
float avg = (float) totalCount * 1000 / (now - startTime); | |
float fps = (float) framesCount * 1000 / fpsTime; | |
Log.i(tag, "FPS = " + fps + ", avg FPS = " + avg); | |
framesCount = 0; | |
lastFpsTrackedTime = now; | |
} | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package com.example.testtest; | |
import android.graphics.drawable.Drawable; | |
import android.os.Handler; | |
import android.os.Message; | |
import android.os.SystemClock; | |
public class LevelAnimator extends Handler { | |
private static final int MSG_ANIMATE = 1; | |
private long startTime, duration; | |
private int begin, end; | |
private final Drawable drawable; | |
public LevelAnimator(final Drawable drawable) { | |
this.drawable = drawable; | |
} | |
@Override | |
public void handleMessage(Message msg) { | |
switch (msg.what) { | |
case MSG_ANIMATE: | |
final int curLevel = getLevelValue(interpolate(getFraction(SystemClock.uptimeMillis()))); | |
drawable.setLevel(curLevel); | |
if (SystemClock.uptimeMillis() < startTime + duration) { | |
sendEmptyMessage(MSG_ANIMATE); | |
} | |
break; | |
default: | |
} | |
} | |
private float getFraction(final long curTime){ | |
float passed = curTime - startTime; | |
final float fraction = passed /duration; | |
return Math.min(fraction, 1.0f); | |
} | |
protected float interpolate(final float fraction) { | |
return fraction; | |
} | |
private int getLevelValue(final float part) { | |
final int interval = end - begin; | |
return begin + (int) (part * interval); | |
} | |
public LevelAnimator setDuration(long duration) { | |
this.duration = duration; | |
return this; | |
} | |
public LevelAnimator start(final int begin, final int end){ | |
startTime = SystemClock.uptimeMillis(); | |
this.begin = begin; | |
this.end = end; | |
sendEmptyMessage(MSG_ANIMATE); | |
return this; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment