Smoke and Mirrors the Magic behind wonderful UI in Android Israel - PowerPoint PPT Presentation
Smoke and Mirrors the Magic behind wonderful UI in Android Israel Ferrer Camacho @rallat Smoke and mirrors N. Amer. the obscuring or embellishing of the truth. Android Framework RecyclerView LayoutManager getViewForPosition RecyclerView
Smoke and Mirrors the Magic behind wonderful UI in Android
Israel Ferrer Camacho @rallat
Smoke and mirrors N. Amer. the obscuring or embellishing of the truth.
Android Framework
RecyclerView LayoutManager getViewForPosition RecyclerView bindViewHolder getViewType getViewHolderByType Adapter RecyclePool
Shared Element Transitions ActivityTransitionState startExit/startEnter ActivityTransitionCoordinator beginDelayedTransition TransitionManager
ViewOverlay LinearLayout ViewOverlay of the LinearLayout ViewOverlay.add( );
ViewOverlay LinearLayout re-layout ViewOverlay of the LinearLayout
/** * A transition listener receives notifications from a transition. * Notifications indicate transition lifecycle events. */ public static interface TransitionListener { void onTransitionStart(Transition transition); void onTransitionEnd(Transition transition); void onTransitionCancel(Transition transition); void onTransitionPause(Transition transition); void onTransitionResume(Transition transition); }
private View.OnTouchListener touchEater = new View.OnTouchListener() { @Override public boolean onTouch(View view, MotionEvent motionEvent) { return true; } };
Important attributes
ClipChildren
<?xml version="1.0" encoding="utf-8"?> <FrameLayout android:id="@+id/parent" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/activity_vertical_margin"> <FrameLayout android:layout_width="300dp" android:layout_height="300dp" android:background="@color/colorAccent" android:clipChildren="false" > <FrameLayout android:layout_width="200dp" android:layout_height="200dp" android:background="@color/colorPrimary"> <ImageView android:id="@+id/imageview" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/profile"/> </FrameLayout> </FrameLayout> </FrameLayout>
<?xml version="1.0" encoding="utf-8"?> <FrameLayout android:id="@+id/parent" xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:clipChildren=“false" android:padding="@dimen/activity_vertical_margin"> <FrameLayout android:layout_width="300dp" android:layout_height="300dp" android:background="@color/colorAccent" android:clipChildren="false" > <FrameLayout android:layout_width="200dp" android:layout_height="200dp" android:background="@color/colorPrimary"> <ImageView android:id="@+id/imageview" android:layout_width="100dp" android:layout_height="100dp" android:src="@drawable/profile"/> </FrameLayout> </FrameLayout> </FrameLayout>
ClipPadding
Utils public static void disableParentsClip(@NonNull View view) { while (view.getParent() != null && view.getParent() instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view.getParent(); viewGroup.setClipChildren(false); viewGroup.setClipToPadding(false); view = viewGroup; } } public static void enableParentsClip(@NonNull View view) { while (view.getParent() != null && view.getParent() instanceof ViewGroup) { ViewGroup viewGroup = (ViewGroup) view.getParent(); viewGroup.setClipChildren(true); viewGroup.setClipToPadding(true); view = viewGroup; }
Smoke and mirrors Lesson: Almost anything fast enough will look good
Smoke and mirrors Lesson: Fake it until you make it.
Demo
Pivot
/** * Sets the x location of the point around which the view * is { @link #setRotation(float) rotated} and * { @link #setScaleX(float) scaled}. * By default, the pivot point is centered on the object. * / smallRecyclerView.setPivotX(0); smallRecyclerView.setPivotY(0); mediumRecyclerView.setPivotX(0); mediumRecyclerView.setPivotY(0);
smallRecyclerView.setAdapter(smallAdapter); mediumRecyclerView.setAdapter(mediumAdapter); mediumRecyclerView.setVisibility( INVISIBLE );
ItemTouchListenerDispatcher dispatcher = new ItemTouchListenerDispatcher(this, galleryGestureDetector, fullScreenGestureDetector); smallRecyclerView.addOnItemTouchListener(onItemTouchListener); mediumRecyclerView.addOnItemTouchListener(onItemTouchListener);
public class ItemTouchListenerDispatcher implements RecyclerView.OnItemTouchListener { … @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { currentSpan = getSpan(e); switch (rv.getId()) { case R.id. mediumRecyclerView : { if (currentSpan < 0) { galleryGestureDetector.onTouchEvent(e); } else if (currentSpan == 0) { final View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY()); if (childViewUnder != null) { childViewUnder.performClick(); } } break; } case R.id. smallRecyclerView : { galleryGestureDetector.onTouchEvent(e); break; } default: { break; } } } …
public class ItemTouchListenerDispatcher implements RecyclerView.OnItemTouchListener { … @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { currentSpan = getSpan(e); switch (rv.getId()) { case R.id. mediumRecyclerView : { if (currentSpan < 0) { galleryGestureDetector.onTouchEvent(e); } else if (currentSpan == 0) { final View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY()); if (childViewUnder != null) { childViewUnder.performClick(); } } break; } case R.id. smallRecyclerView : { galleryGestureDetector.onTouchEvent(e); break; } default: { break; } } } …
public class ItemTouchListenerDispatcher implements RecyclerView.OnItemTouchListener { … @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { currentSpan = getSpan(e); switch (rv.getId()) { case R.id. mediumRecyclerView : { if (currentSpan < 0) { galleryGestureDetector.onTouchEvent(e); } else if (currentSpan == 0) { final View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY()); if (childViewUnder != null) { childViewUnder.performClick(); } } break; } case R.id. smallRecyclerView : { galleryGestureDetector.onTouchEvent(e); break; } default: { break; } } } …
public class ItemTouchListenerDispatcher implements RecyclerView.OnItemTouchListener { … @Override public void onTouchEvent(RecyclerView rv, MotionEvent e) { currentSpan = getSpan(e); switch (rv.getId()) { case R.id. mediumRecyclerView : { if (currentSpan < 0) { galleryGestureDetector.onTouchEvent(e); } else if (currentSpan == 0) { final View childViewUnder = rv.findChildViewUnder(e.getX(), e.getY()); if (childViewUnder != null) { childViewUnder.performClick(); } } break; } case R.id. smallRecyclerView : { galleryGestureDetector.onTouchEvent(e); break; } default: { break; } } } …
Scaling with gesture
public interface OnScaleGestureListener { /** * Responds to scaling events for a gesture in progress. * Reported by pointer motion. */ public boolean onScale(ScaleGestureDetector detector); /** * Responds to the beginning of a scaling gesture. Reported by * new pointers going down. */ public boolean onScaleBegin(ScaleGestureDetector detector); /** * Responds to the end of a scale gesture. Reported by existing * pointers going up. * @param detector The detector reporting the event - use this to * retrieve extended info about event state. */ public void onScaleEnd(ScaleGestureDetector detector); }
Scale begin @Override public boolean onScaleBegin(@NonNull ScaleGestureDetector detector) { mediumRecyclerView.setVisibility(View. VISIBLE ); smallRecyclerView.setVisibility(View. VISIBLE ); return true; }
Recommend
More recommend
Explore More Topics
Stay informed with curated content and fresh updates.