Android UI Tips & Tricks

Post on 13-Nov-2014

401 views 2 download

Tags:

description

Shem will share development tips while explaining how things work under-the-hood. As part of his talk, he will demonstrate the right way of working with images, custom views, ListViews and Animations, with an emphasis of how to make your app feel slick and fast on all Android devices.

Transcript of Android UI Tips & Tricks

Android UI Tips & Tricks

Shem Magnezi

Making your good app great

Know your app

Understand what you

need

No magic/ generic

solutions

You know how to write a good

app

Looks good Feel slick

Not gonna talk about

viral/ design/ downloads

etc...

Agenda

● Working with images● Bring your views into life with

animations● Upgrade your lists views

Working with images

Images in memory

Bitmap memory size:Bitmap.getWidth() * Bitmap.getHeight() * Bitmap.config

Determine how much the bitmap gonna take:Image.width * Image.height * Options.config / Options.sampleSize

Cache Cache Cache

● Use cache for performance● Be careful not using too much memory

Determine your cache size

● Approximate per-application memory: getSystemService(Context.ACTIVITY_SERVICE).getMemoryClass()

● Pay attention to: onTrimMemory(int level) on your Application

● Profile your memory usage live

Loading the proper image type

For small image views work with thumbnails:MediaStore.Images.Thumbnails.getThumbnail(

..., int kind, ...)

MINI_KIND: 512 x 384

MICRO_KIND: 96 x 96

Sample size

Original size is probably too big, so load smaller size.

Original

inSampleSize=2

memory/4

Determine the right sample size

● Get the original image size using: options.inJustDecodeBounds = true;

● Get the view that gonna present the image● Find the minimum sample_size so:

o image.width / sample_size > view.width o image.height / sample_size > view.heighto it also prefer that sample_size will be power of 2 for

faster/ easier decoding

Find your view size

Sometimes your view size is 0 (cause is not yet drawn), so you should wait until the system will draw it:

view.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {

public void onGlobalLayout() {//load image for the right size

}});

}

Determine image sizeCENTER_CROP

float scale = Math.max(viewW / imgW, viewH / imgH)

float scaledWidth = scaale * viewW;

float scaledHeight = scale * viewHt;

CENTER_INSIDE

float scale = Math.min(viewW / imgW, viewH / imgH)

float scaledWidth = scaale * viewW;

float scaledHeight = scale * viewHt;

Make your cache a bit smarterget(Item image, Size size) {

cached = getImage(image);if (cached != null) {

if (cached.size >= size) {

//saved time!

} else {//maybe

display a lower //resolution until loading

//the full image}

} else {//photo not in cache,

but we//did our best}}

put(Item image, Size size) {if (size < MICRO_KIND_SIZE) {

//load micro kind thumbnail

} else if (size < MINI_KIND_SIZE) {

//load mini kind thumbnail

} else {//read the full image

with the//right sample size

}}

Bitmap config

ARG_565 has no alpha channel and is it in lower quality

But:● It’s ~x2 faster to load● It consume half of the

memory● Most of the time you

won’t see any differencesource: Romain Guy

Animations

Interpolator

Sometimes you can use interpolator instead of couple of sequenced animations.For example, the built-in bounce animation on android.

Between-activities animationsSet activity style:<item name="android:windowBackground">@android:color/transparent</item>

When moving to this activity:startActivity(intent);overridePendingTransition(0, 0);

Do the animation:ViewTreeObserver observer = animationImage.getViewTreeObserver();observer.addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {

public boolean onPreDraw() {animationImage.getViewTreeObserver().removeOnPreDrawListener(this); runEnterAnimation(back, startBounds);}});

Pre drawer listener?

Very useful for animations!● Create enter animation to your activity● Create animation to your view when

it’s added to the screen● Animate list items when the list

changes

Smart image animation

Case #1Scaling animation for the image view:ObjectAnimator.ofFloat(image_1, "scaleY", 1, 1.5f);

<ImageViewandroid:id="@+id/image_1" android:layout_width="225dp"android:layout_height="150dp"android:scaleType="centerCrop"/>

When animating the view there is no re-layout and the image not preserving it’s scale type

Case #2Use a frame and do a reverse scaling to the inner image:<RelativeLayout android:id="@+id/image_2"

android:layout_width="225dp"android:layout_height="150dp"> <ImageView android:id="@+id/inner_image"android:layout_width="225dp"android:layout_height="300dp"android:layout_marginTop="-75dp" android:layout_marginBottom="-

75dp"/></RelativeLayout>

anim.playTogether(ObjectAnimator.ofFloat(image_2, "scaleY", 1,

1.5f), ObjectAnimator.ofFloat(inner, "scaleY", 1f, 0.6666f));

● Lots of calculations

● The animation is not linear

● Need an extra view

Case #3Use an extra image as the target view:anim.playTogether(ObjectAnimator.ofFloat(image_3, "scaleY", 0.6666f, 1f),ObjectAnimator.ofFloat(image_3, "alpha", 0, 1));

<ImageViewandroid:id="@+id/image_3" android:layout_width="225dp"android:layout_height="225dp"android:scaleType="centerCrop"/>

● You are losing the original view

● The animation isn’t smooth

Case #4Implement you own Animation:public class ExpandAnimation extends Animation {

protected void applyTransformation(float inp ...) {...if (inp < 1.0f) {

lp.height =(int)(start + (end - start)* inp);mAnimatedView.requestLayout();

}}

<ImageView android:id="@+id/image_4"android:layout_width="225dp"

android:layout_height="150dp" android:scaleType="centerCrop" />

Working with Lists

The basic things

● Reuse items● ViewHolder pattern● Long tasks should run in background

with AsyncTask● Cancel view loading tasks using

RecyclerListener

● Use ListFragment

Profile your drawing

● Design your layout as flat as you can● Avoid over drawing or nested weights● Profile your list using GPU overdraw

and GPU Rendering in developer options

Empty view in your ListFragment

Use android:id="@android:id/empty"

for the case the list is empty

<ListView android:id="@android:id/list" … /><RelativeLayout android:id="@android:id/empty" ... />

Save each item state

In your adapter:Set<Integer> opened = HashSet<Integer>();

On widget opened:opened.add(item.getId());

In getView():view.setOpened(opened.contains(item.getId());

Scrolled view inside ListViewYou sometime want to put a view that can be scrolled by himself as one of your listview items- for example putting a grid view of images.For doing it you must let layout manager that this view must take it’s full size:

@Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

int heightSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,

MeasureSpec.AT_MOST);

super.onMeasure(widthMeasureSpec, heightSpec);

getLayoutParams().height = getMeasuredHeight();

}

source: stackoverflow.com

Smart scrollbar for easy navigation

● Put a relative view that contains your list view and set him as a OnScrollListener

● On onScroll calc the right position of your scroller view using totalItemCount and visibleItemCount

● On draw put your scroller view using setTranslationY

Smart scrollbar for easy navigationYou can even add a behavior for dragging the scroller using onTouchEvent:public boolean onTouchEvent(MotionEvent event) {

if (event.getAction() == MotionEvent.ACTION_DOWN) {if (//event in scroll bar view)

mDragging = true;} else if (me.getAction() == MotionEvent.ACTION_UP) {

if (mDragging) mDragging = false;} else if (me.getAction() == MotionEvent.ACTION_MOVE) {

if (mDragging)mList.setSelectionFromTop(//calc the right item index, 0);}}

</presentation>

Thank you.