Android UI Tips & Tricks
-
Upload
droidcontlv -
Category
Technology
-
view
401 -
download
2
description
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.