Improving android experience for both users and developers
-
Upload
pavel-lahoda -
Category
Technology
-
view
207 -
download
3
description
Transcript of Improving android experience for both users and developers
IMPROVING ANDROID EXPERIENCE FOR BOTH USERS AND DEVELOPERS
droidcon Berlin 2013, Pavel Lahoda, Actiwerks Ltd.
LET’S HAVE A LITTLE WARMUP
ANDROID.UTIL.LOG
HOW MANY TIMES YOU’VE TYPED THIS ?
prn.log("Index=" + i);
HOW ABOUT THIS ?
public static String cc(int depth) { if(skipCallStackCode == true) { return NA; // short-circuit for production } StackTraceElement[] ste = getStackTrace(null); int depthCount = 0; boolean shallowFlag = true; for(StackTraceElement element : ste) { if(prn.class.getName().equals(element.getClassName()) == true) { // always ignore elements that are above this class in the stack shallowFlag = false; } else { if(shallowFlag == false) { if(depthCount >= depth) { String name = element.getFileName(); if(name != null) { if(name.endsWith(".java")) { name = name.substring(0, name.length()-5); } } else { name ="[?]"; } return name; } else { depthCount++; } } } } return NA_BUG; }
HOW DOES IT WORK ?
GITHUB LINK
WHERE IS THE UX ?
HAVE TIME TO WORK ON AWESOME STUFF !
IMPORTANCE OF HAVING YOUR VIEW FLEXIBLE
ANDROID AND WEB COMMON STUFFUNLIMITED AMOUNT OF DISPLAY SIZES
WEB TRENDS: RESPONSIVE DESIGN
ANDROID TRENDS: LOTS OF WORK
CURRENT ANDROID LAYOUTS ARE NOT FLEXIBLE ENOUGH
ALTERNATIVE:USE PURE JAVA VIEWGROUP
@Overrideprotected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthSpecSize = View.MeasureSpec.getSize(widthMeasureSpec); tinyGap = widthSpecSize/100; myComponent.measure(View.MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY), View.MeasureSpec.makeMeasureSpec(LayoutParams.WRAP_CONTENT, View.MeasureSpec.EXACTLY));
// more component’s measuring goes there setMeasuredDimension(widthSpecSize, newHeight);}
@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {
myComponent.layout(x, y, x+myComponent.getMeasuredWidth(), y+titleLabel.getMeasuredHeight());// more component’s layout goes there
}
ONMEASURE() - PLACE FOR YOUR LOGIC
NO NEED TO REBIND COMPONENTS OR CALL SLOW LAYOUT INFLATE CODE
WORKS GREAT FOR ORIENTATION CHANGES
BBC NEWS FOR TABLETS EXAMPLE
INSPIRATION:WEB RESPONSIVE LAYOUT
DEAL WITH MANY DIFFERENT SCREEN SIZES
STANDOUT - FLOATING WINDOWS
ACTION BAR
ONE OF WORST EXAMPLES OF API DESIGN
ACTIONBAR IS NOT A DESCENDANT OF A VIEW
BLOG.PERPETUMDESIGN.COM/2011/08/STRANGE-CASE-OF-DR-ACTION-AND-
MR-BAR.HTML
ACTIONBARSHERLOCK
ACTION BAR PLUS
PROBLEM ?
AB OCCUPIES ~10% OF SCREEN SPACE
FUNCTIONALITY OFTEN REDUCED TO BRANDING
FLY-OUT MENU: A FACEBOOK SOLUTION
NOT CONSISTENT WITH THE REST OF ACTIONBAR FUNCTIONALITY
ACTIONBAR PARTS
ACTIONBAR BEHAVIOR
Touch here showsa menu with options
Touch here moves up in hierarchy
Touch here performs action
Touch here show a menu with options
Any extension should stay consistent with this
DON’T CONFUSE YOUR USERS
OWN APPS’D USE SOME UX FACELIFT
STILL WANT MORE FROM THE ACTIONBAR AREA ?
ACTION BAR PLUSCUSTOM ACTIONBAR IMPLEMENTATION
EMBRACE EXTRA DIMENSION
TWO TYPES OF NAVIGATION
MAKE SURE THERE IS DEAD AREA TO SEPARATE FROM NOTIFICATION BAR
GESTURE
USE MIDDLE AS BONUS CONTENT
SUCH AS STUFF OUTSIDE THE APP
2D JUST ON OVERFLOWACTIONS ARE EITHER TOUCH
OR SWIPE DOWN
ACCESS TO HELP ON ACTIONS
EMBRACE MULTITOUCH
EASY SPLIT VIEW FEATURE
BROADCAST THE AVAILABLE SCREEN
actiwerks.intent.splitviewDESCRIPTION OF THE INTENT APPEARS SOON ON THE OPENINTENTS.ORG
BROADCAST DETAILS
private Intent splitIntent;
splitIntent = new Intent();splitIntent.setAction("actiwerks.intent.splitview");
splitIntent.removeExtra("APP_SPLIT_SIZE");splitIntent.putExtra("APP_SPLIT_SIZE", windowVerticalOffset);getContext().sendBroadcast(splitIntent);
RECEIVE THE BROADCAST
<receiver android:name="AppSplitViewReceiver" ><intent-filter>
<action android:name="actiwerks.intent.splitview" /></intent-filter>
</receiver>
public class AppSplitViewReceiver extends BroadcastReceiver {
@Override public void onReceive(Context context, Intent intent) { if(intent.getAction() != null && intent.getAction().equals("actiwerks.intent.splitview")) { int peekSize = intent.getIntExtra("APP_SPLIT_SIZE", -1); // Handle the intent in the app, resize the window/layout accordingly } }
}
ACTIONBARPLUS IN THE GITHUB
FUN WITH THE LIST VIEW
PROBLEM ?
ARRAYADAPTER API NOT DESIGNEDFOR GENERIC VIEWGROUP
interface ViewAdapterBinder<T, V> {public void bindViewToData(V view, T data);
}
public class ArrayViewGroupAdapter<T, V extends ViewGroup> extends ArrayAdapter<T>
BIND DATA TO VIEW
public View getView(int position, View convertView, ViewGroup parent){ // assign the view we are converting to a local variable V v = null; try { v = (V) convertView; } catch(ClassCastException ccex) {}
// safe to ignore, keep null to force new instance to be created
// first check to see if the view is null. if so, we have to inflate it. // to inflate it basically means to render, or show, the view. if (v == null) { v = getInstanceOfV(); } T data = getItem(position); if (data != null && binder != null) { binder.bindViewToData(v, data); } else { // signal error here prn.log("Can't bind data to view " + position); } // the view must be returned to our activity return v;
}
private V getInstanceOfV() {
ParameterizedType superClass = (ParameterizedType) getClass().getGenericSuperclass();
Class<V> type = (Class<V>) superClass.getActualTypeArguments()[1];
try { return type.getDeclaredConstructor(Context.class).newInstance(getContext());
} catch (Exception ex) {// Oops, no default constructorthrow new RuntimeException(ex);
}
}
public class SampleArrayAdapter extends ArrayViewGroupAdapter<SampleData, SampleListItem> {
public SampleArrayAdapter(Context context) { super(context, new ArrayViewGroupAdapter.ViewAdapterBinder<SampleData, SampleListItem>() { @Override public void bindViewToData(SampleListItem view, SampleData data) { view.setTitle(data.getTitle()); view.setDetails(data.getDetails()); } }); }}
A TYPE-SAFE, REFACTORING FRIENDLY SOLUTION
ADVANTAGES FOR THE DEVELOPER AND THE USER
INSTANT LISTS WITH INTROSPECTION
OBJECTFORMS.COM
FLEXIBLE LAYOUT ALLOWS RESIZING
PINCH TO ZOOM GESTURE IN LISTS
TIME AND DATE PICKER
PROBLEM ?
UNLIKE OTHER WIDGETS, TIME & DATE PICKER NEEDS DIALOG
(OR PLENTY OF SPACE)
SOLUTION:SPLIT EDITING INTO SPECIALIZED
TIME & DATE KEYBOARD
DIRECT MANIPULATION GESTURE
“KEYBOARD” FOR DATE SELECTION
NO TOUCH AT ALL
KINETIC GESTURES
SHAKE GESTURE
- (void)motionEnded:(UIEventSubtype)motion withEvent:(UIEvent *)event{ if (motion == UIEventSubtypeMotionShake) { [self showAlert]; }} //When a gesture is detected (and ended) the showAlert method is called. -(IBAction)showAlert{ UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"ShakeGesture Demo" message:@"Shake detected" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show];}
AREA THAT IS NOT GETTING THE LOVE IT DESERVERS
TIM BRAY : SENSPLORE
SENSOR FUSION
http://www.youtube.com/
watch?v=C7JQ7Rpwn2k
SAMSUNG GESTURES
HELP US SHAPE THE FUTURE
http://www.kineticgestures.org
TAKEWAY
Q & A
THANK YOU