Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Custom Layouts

Custom Layouts

Presented at Droidcon London 2014

Lucas Rocha

October 31, 2014
Tweet

More Decks by Lucas Rocha

Other Decks in Programming

Transcript

  1. STRUCTURE public class TweetLayout extends ViewGroup { public TweetLayoutView(Context context,

    AttributeSet attrs) { super(context, attrs, defStyleAttr); LayoutInflater.from(context) .inflate(R.layout.tweet_layout, this, true); mProfileImage = (ImageView) findViewById(R.id.profile_image); ... } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ... } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { ... } }
  2. LAYOUT FILE <merge xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <ImageView android:id="@+id/profile_image" android:layout_width="@dimen/tweet_profile_image_size" android:layout_height="@dimen/tweet_profile_image_size"

    android:scaleType="centerCrop"/> <TextView android:id="@+id/author_text" android:layout_width="fill_parent" android:layout_height="wrap_content" android:textSize="@dimen/tweet_author_text_size" android:singleLine="true"/> ... </merge>
  3. MEASURE @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { ...

    int widthUsed = 0; int heightUsed = 0; measureChildWithMargins(mProfileImage, widthMeasureSpec, widthUsed, heightMeasureSpec, heightUsed); widthUsed += getMeasuredWidthWithMargins(mProfileImage); measureChildWithMargins(mAuthorText, widthMeasureSpec, WidthUsed, heightMeasureSpec, heightUsed); heightUsed += getMeasuredHeightWithMargins(mAuthorText); measureChildWithMargins(mMessageText, widthMeasureSpec, WidthUsed, heightMeasureSpec, heightUsed); heightUsed += getMeasuredHeightWithMargins(mMessageText); ... setMeasuredDimension(widthSize, heightSize); }
  4. LAYOUT @Override protected void onLayout(boolean changed, int l, int t,

    int r, int b) { int currentTop = paddingTop; layoutView(mProfileImage, paddingLeft, currentTop, mProfileImage.getMeasuredWidth(), mProfileImage.getMeasuredHeight()); final int contentLeft = getWidthWithMargins(mProfileImage) + paddingLeft; final int contentWidth = r - l - contentLeft - getPaddingRight(); layoutView(mAuthorText, contentLeft, currentTop, contentWidth, mAuthorText.getMeasuredHeight()); currentTop += getHeightWithMargins(mAuthorText); layoutView(mMessageText, contentLeft, currentTop, contentWidth, mMessageText.getMeasuredHeight()); currentTop += getHeightWithMargins(mMessageText); ... }
  5. LOW-LEVEL 1. Track visible viewport 2. Recycle views out of

    bounds 3. Appearing/disappearing views 4. Scroll to position 5. State restoration ...
  6. STRUCTURE public class SimpleListLayout extends TwoWayLayoutManager { public SimpleListLayout(Context context,

    Orientation orientation) { super(context, orientation); } @Override protected void measureChild(View child, Direction direction) { ... } @Override protected void layoutChild(View child, Direction direction) { ... } @Override protected boolean canAddMoreViews(Direction direction, int limit) { ... } }
  7. LAYOUT @Override protected void layoutChild(View child, Direction direction) { final

    int width = getDecoratedMeasuredWidth(child); final int height = getDecoratedMeasuredHeight(child); final int l, t, r, b; if (getOrientation() == Orientation.VERTICAL) { l = getPaddingLeft(); t = direction == Direction.END ? getLayoutEnd() : getLayoutStart() - height; } else { l = direction == Direction.END ? getLayoutEnd() : getLayoutStart() - width; t = getPaddingTop(); } r = l + width; b = t + height; layoutDecorated(child, l, t, r, b); }
  8. VIEWPORT CONTROL @Override protected boolean canAddMoreViews(Direction direction, int limit) {

    if (direction == Direction.END) { return getLayoutEnd() < getEndWithPadding(); } else { return getLayoutStart() > getStartWithPadding(); } }