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

Droidcon Boston 2017: Cool ConstraintLayout

Droidcon Boston 2017: Cool ConstraintLayout

Huyen's presentation at Droidcon Boston 2017 on some of the cool things that you can do with ConstraintLayout.

Huyen Tue Dao

April 11, 2017
Tweet

More Decks by Huyen Tue Dao

Other Decks in Programming

Transcript

  1. HUYEN TUE DAO
    @QUEENCODEMONKEY
    COOL
    CONSTRAINT
    LAYOUT
    #DROIDCONBOS

    View Slide

  2. COOL THINGS ABOUT
    CONSTRAINT LAYOUT
    COOL THINGS TO DO
    WITH CONSTRAINT LAYOUT
    #DROIDCONBOS

    View Slide

  3. WHAT IS THE
    CONSTRAINT
    LAYOUT?
    #DROIDCONBOS

    View Slide

  4. EXPRESSIVE
    RELATIONSHIPS BETWEEN VIEWS
    RELATIVE LAYOUT++
    +≈ LINEARLAYOUT
    PERFORMANT
    #DROIDCONBOS

    View Slide

  5. UNBUNDLED
    SUPPORTS API 9+
    UI BUILDER
    USABLE WITH XML ONLY
    #DROIDCONBOS

    View Slide

  6. HOW DOES IT
    WORK?
    #DROIDCONBOS

    View Slide

  7. CONSTRAINTS
    EQUATIONS
    SOLVER
    7
    HOW DOES IT WORK?

    View Slide

  8. CONSTRAINTS
    EQUATIONS
    SOLVER
    POSITION
    FIXED
    WRAP CONTENT
    MATCH CONSTRAINT
    RATIO
    EDGE
    CENTER
    BASELINE
    DIMENSION
    HELPERS/GROUPINGS
    GUIDELINE CONSTRAINTSET
    CHAINS
    8
    HOW DOES IT WORK?

    View Slide

  9. CONSTRAINTS
    EQUATIONS
    SOLVER
    LINEAR SYSTEM
    OF EQUATIONS
    9
    HOW DOES IT WORK?

    View Slide

  10. CONSTRAINTS
    EQUATIONS
    SOLVER
    CASSOWARY
    LINEAR ARITHMETIC
    CONSTRAINT SOLVING
    ALGORITHM
    VIEW BOUNDS
    10
    HOW DOES IT WORK?

    View Slide

  11. CONSTRAINTLAYOUT, INSIDE AND OUT: PART 2
    DAVE SMITH

    View Slide

  12. LET’S TAKE
    A QUICK
    TOUR
    #DROIDCONBOS

    View Slide

  13. View Slide

  14. CONSTRAINT
    LAYOUT CHEAT
    SHEET
    #DROIDCONBOS

    View Slide

  15. SOURCE
    TARGET
    EDGE CONSTRAINT
    #DROIDCONBOS

    app:layout_constraintLeft_toLeftOf="parent"

    app:layout_constraint_toOf=“a_view"

    View Slide

  16. #DROIDCONBOS
    CENTER CONSTRAINT

    app:layout_constraintHorizontal_bias="0.75"

    View Slide

  17. #DROIDCONBOS
    BASELINE CONSTRAINT
    app:layout_constraintBaseline_toBaselineOf="@+id/view"

    View Slide

  18. #DROIDCONBOS SIZE CONSTRAINTS

    View Slide

  19. #DROIDCONBOS GUIDELINES

    View Slide

  20. android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:id="@+id/guideline_start"

    android:orientation="vertical"

    app:layout_constraintGuide_begin="16dp" />



    android:layout_width="wrap_content"

    android:layout_height="wrap_content"

    android:id="@+id/horizontal"

    android:orientation="horizontal"

    app:layout_constraintGuide_percent="0.37" />
    #DROIDCONBOS

    View Slide

  21. SO WHAT CAN
    WE DO WITH
    CONSTRAINT
    LAYOUT?
    #DROIDCONBOS

    View Slide

  22. public class SquareImageView extends ImageView {
    @Override

    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

    super.onMeasure(widthMeasureSpec, heightMeasureSpec);


    final int size = Math.min(getMeasuredWidth(), getMeasuredHeight());

    setMeasuredDimension(size, size);

    }
    #DROIDCONBOS

    View Slide

  23. android:id=“@+id/square_image”

    android:layout_width="0dp"

    android:layout_height="0dp"

    app:layout_constraintDimensionRatio=“W,1:1"
    #DROIDCONBOS

    View Slide

  24. #DROIDCONBOS

    View Slide

  25. IS IT REALLY
    BETTER THAN
    RELATIVE
    LAYOUT?
    #DROIDCONBOS

    View Slide

  26. #DROIDCONBOS

    View Slide

  27. #DROIDCONBOS

    View Slide

  28. private fun updateManualAnchors() {

    val size = anchorMinSize + seekBar.progress

    val halfSize = Math.round(size * 0.5f)

    val horizontalMargin =
    resources.getDimensionPixelSize(R.dimen.content_margin_horizontal) - halfSize

    val verticalMargin =
    resources.getDimensionPixelSize(R.dimen.alignment_rectangle_margin_vertical) - halfSize

    updateManualAnchor(frameAnchorTop, size, verticalMargin, 0, 0, 0)

    updateManualAnchor(frameAnchorStart, size, 0, horizontalMargin, 0, 0)

    updateManualAnchor(frameAnchorBottom, size, 0, 0, verticalMargin, 0)

    updateManualAnchor(frameAnchorEnd, size, 0, 0, 0, horizontalMargin)

    }


    private fun updateManualAnchor(anchor: View, size: Int,

    marginTop: Int, marginStart: Int,

    marginBottom: Int, marginEnd: Int) {

    val layoutParams = anchor.layoutParams as FrameLayout.LayoutParams
    layoutParams.width = size

    layoutParams.height = size

    layoutParams.topMargin = marginTop

    layoutParams.bottomMargin = marginBottom

    layoutParams.marginStart = marginStart

    layoutParams.marginEnd = marginEnd
    anchor.layoutParams = layoutParams

    }
    WITH CONSTRAINTLAYOUT
    JUST CHANGE THE SIZE…

    View Slide

  29. WHAT WAS THAT
    ABOUT LINEAR
    LAYOUT?
    #DROIDCONBOS

    View Slide

  30. CHAINS. CHAINS. CHAINS.
    FROM CONSTRAINTLAYOUT DOCUMENTATION #DROIDCONBOS

    View Slide

  31. android:id=“@+id/head_of_spread_inside”

    app:layout_constraintHorizontal_chainStyle="spread_inside"

    … />
    SPREAD INSIDE CHAIN

    View Slide

  32. android:id=“@+id/weighted_chain_head

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    app:layout_constraintHorizontal_chainStyle="spread"

    app:layout_constraintHorizontal_weight=“1" />
    android:id=“@+id/next
    android:layout_width="0dp"

    android:layout_height="wrap_content"

    app:layout_constraintHorizontal_weight="2" />
    android:id=“@+id/last

    android:layout_width="0dp"

    android:layout_height="wrap_content"

    app:layout_constraintHorizontal_weight="1" />
    32
    WEIGHTED CHAIN

    View Slide

  33. android:id=“@+id/packed_chain_head”

    app:layout_constraintHorizontal_chainStyle="packed"

    app:layout_constraintHorizontal_bias="0.12" />
    33
    PACKED CHAIN

    View Slide

  34. #DROIDCONBOS

    View Slide

  35. #DROIDCONBOS

    View Slide

  36. A CONSTRAINT
    LAYOUT SPECIAL
    CONSTRAINT SET
    #DROIDCONBOS

    View Slide

  37. CONSTRAINT SET
    #DROIDCONBOS
    DEFINE SET OF CONSTRAINTS
    PROGRAMMATICALLY
    CREATE/SAVE/APPLY
    CREATE MANUALLY
    CLONE A LAYOUT FILE
    CLONE A CONSTRAINT LAYOUT
    AWESOME WITH TRANSITIONS

    View Slide

  38. View Slide

  39. View Slide

  40. // Inflate initial layout as usual.
    setContentView(R.layout.activity_constraintset_01)
    // Get references to controls

    constraintLayout = findViewById(R.id.constraint_layout) as ConstraintLayout


    // Load ConstraintSets.

    constraintSet01.clone(constraintLayout)

    constraintSet02.clone(this, R.layout.activity_constraintset_02)
    …some time later…
    // Toggle ConstraintSets.
    TransitionManager.beginDelayedTransition(constraintLayout)

    if (original) constraintSet02.applyTo(constraintLayout)

    else constraintSet01.applyTo(constraintLayout)

    original = !original
    38

    View Slide

  41. CONSTRAINT SET
    IN LIEU OF
    CUSTOM
    VIEWGROUP
    #DROIDCONBOS

    View Slide

  42. CUSTOM VIEW
    GROUP
    #DROIDCONBOS
    LAYOUT IS LOW-LEVEL (X, Y)
    LOTS OF CODE TO ACCOMPLISH A
    SIMPLE LAYOUT
    ADVANCED LAYOUTS… WOAH

    View Slide

  43. @Override

    protected void onLayout(boolean changed, int left, int top, int right, int bottom) {

    MarginLayoutParams layoutParams = (MarginLayoutParams) icon.getLayoutParams();


    // Figure out the x-coordinate and y-coordinate of the icon.

    int x = getPaddingLeft() + layoutParams.leftMargin;

    int y = getPaddingTop() + layoutParams.topMargin;


    // Layout the icon.

    icon.layout(x, y, x + icon.getMeasuredWidth(), y + icon.getMeasuredHeight());


    // Calculate the x-coordinate of the title: icon's right coordinate +

    // the icon's right margin.

    x += icon.getMeasuredWidth() + layoutParams.rightMargin;


    // Add in the title's left margin.

    layoutParams = (MarginLayoutParams) titleView.getLayoutParams();

    x += layoutParams.leftMargin;


    // Calculate the y-coordinate of the title: this ViewGroup's top padding +

    // the title's top margin

    y = getPaddingTop() + layoutParams.topMargin;


    // Layout the title.

    titleView.layout(x, y, x + titleView.getMeasuredWidth(), y + titleView.getMeasuredHeight());


    // The subtitle has the same x-coordinate as the title. So no more calculating there.


    // Calculate the y-coordinate of the subtitle: the title's bottom coordinate +

    // the title's bottom margin.

    y += titleView.getMeasuredHeight() + layoutParams.bottomMargin;

    layoutParams = (MarginLayoutParams) subtitleView.getLayoutParams();


    // Add in the subtitle's top margin.

    y += layoutParams.topMargin;


    // Layout the subtitle.

    subtitleView.layout(x, y,

    x + subtitleView.getMeasuredWidth(), y + subtitleView.getMeasuredHeight());

    }

    View Slide

  44. CONSTRAINT SET
    IN LIEU OF
    CUSTOM
    VIEWGROUP
    #DROIDCONBOS

    View Slide

  45. private fun addRow(view: View) {

    constraintLayout.addView(view)


    val id = view.id

    constraintSet.constrainWidth(id, MATCH_CONSTRAINT)

    constraintSet.constrainHeight(id, rowHeight)


    // Constrain new view vertically.

    val target = if (lastRowId  PARENT_ID) TOP else BOTTOM

    constraintSet.connect(id, TOP, lastRowId, target)
    // Constrain new view horizontally.

    constraintSet.connect(id, START, PARENT_ID, START)

    constraintSet.connect(id, END, PARENT_ID, END)


    // Toggle elevation to elevate last added view.

    constraintSet.setElevation(id,
    resources.getDimension(R.dimen.elevation_content))

    constraintSet.setElevation(lastViewId, 0f)


    // Apply constraints.

    constraintSet.applyTo(constraintLayout)
    43

    View Slide

  46. private fun addRowItem(view: View) {

    …

    constraintLayout.addView(view)


    val id = view.id


    // Initialize width and height of new view.

    constraintSet.constrainWidth(id, MATCH_CONSTRAINT)

    constraintSet.constrainHeight(id, rowHeight)


    // Constrain new view vertically.

    val target = if (lastRowId  PARENT_ID) TOP else BOTTOM

    constraintSet.connect(id, TOP, lastRowId, target)
    44

    View Slide

  47. // Update current row.

    currentRow.add(id)

    // Re-create horizontal chain with other row items.

    constraintSet.createHorizontalChainRtl(

    PARENT_ID, START,

    PARENT_ID, END,

    currentRow.toIntArray(), FloatArray(currentRow.size, { 1f }),

    CHAIN_SPREAD_INSIDE)


    // Toggle elevation to elevate last added view.

    constraintSet.setElevation(id,
    resources.getDimension(R.dimen.elevation_content))

    constraintSet.setElevation(lastViewId, 0f)


    // Apply constraints.

    constraintSet.applyTo(constraintLayout)
    45

    View Slide

  48. SERIOUSLY
    COOL THINGS IN
    CONSTRAINT
    LAYOUT
    #DROIDCONBOS

    View Slide

  49. ANDROID DEVELOPERS BACKSTAGE
    EPISODE 50: CONSTRAINT LAYOUT

    View Slide

  50. CONSTRAINTLAYOUT CREW
    JOHN HOFORD
    @JOHNHOFORD
    NICOLAS ROARD
    @CAMAELON
    #DROIDCONBOS

    View Slide

  51. THANK YOU!
    SPEAKERDECK.COM/QUEENCODEMONKEY
    YOUTUBE.COM/ANDROIDDIALOGS
    RANDOMLYTYPING.COM
    HUYEN TUE DAO
    @QUEENCODEMONKEY
    #DROIDCONBOS

    View Slide

  52. REFERENCES
    50
    CONSTRAINT LAYOUT APIS DOCUMENTATION
    https://developer.android.com/reference/android/support/constraint/package-summary.html
    BUILD A RESPONSIVE UI WITH CONSTRAINTLAYOUT
    developer.android.com/training/constraint-layout/index.html
    ANDROID DEVELOPERS BACKSTAGE: EPISODE 50: CONSTRAINT LAYOUT
    androidbackstage.blogspot.com/2016/06/episode-50-constraint-layout.html
    USING CONSTRAINTLAYOUT TO DESIGN YOUR VIEWS | CODE LABS
    codelabs.developers.google.com/codelabs/constraint-layout/index.html
    ANDROID LAYOUTS: A NEW WORLD | GOOGLE I/O 2016
    https://youtu.be/sO9aX87hq9c
    CONSTRAINTLAYOUT
    https://speakerdeck.com/writtmeyer/constraintlayout-1
    ADVANCED CONSTRAINTLAYOUT
    http://cfp.devoxx.us/2017/talk/XOD-8930/Advanced_ConstraintLayout

    View Slide

  53. REFERENCES
    51
    CONSTRAINTLAYOUT – PART 1
    blog.stylingandroid.com/constraintlayout-part-1/
    CONSTRAINTLAYOUT, INSIDE AND OUT: PART 1
    http://wiresareobsolete.com/2016/07/constraintlayout-part-1/
    SOME THOUGHTS ON ANDROID’S NEW CONSTRAINTLAYOUT AND ANDROID STUDIO’S NEW DESIGN EDITOR
    http://www.grokkingandroid.com/thoughts-on-constraintlayout-and-design-editor/
    BUILD A UI WITH LAYOUT EDITOR
    developer.android.com/studio/write/layout-editor.html
    WHAT'S NEW IN ANDROID DEVELOPMENT TOOLS | GOOGLE I/O 2016
    https://youtu.be/csaXml4xtN8
    THE EXPERTS' GUIDE TO ANDROID DEVELOPMENT TOOLS | GOOGLE I/O 2016
    https://youtu.be/hHnTIMjd1Y8

    View Slide