layout: false ![:img Windows tablet screen with a grid of interactive squares... icons along the side for invoking menus... and a colorful background picture,70%](img/layout/windowsLayout.png) ??? Key Issues - where do components get placed? - how much space should they occupy? --- name: inverse layout: true class: center, middle, inverse --- # Introduction to Layout Lauren Bricker CSE 340, Winter 2020 --- name: normal layout: true class: --- layout: false [//]: # (Outline Slide) .left-column[ # Today's goals ] .right-column[ - Announcements - Review of tree construction - Using tree for layout - Container components ] --- # Announcements - Reminder: midterm exam on 2/7 during class - Any midterm exam conflicts? We will be having an alt exam, but - You need a good reason - You need to notify us at least 48 hours in advance, preferably a week. - The alt exam will be within 2 school days of the regular time. - Any questions? Please contact Jen! --- # Hall of Shame (from [CSE 154](https://courses.cs.washington.edu/courses/cse154/19au/lectures/lec05-css-iii-more-layout/index.html#/)) ![:img Terrible website from gatesnfences.com, 50%](https://courses.cs.washington.edu/courses/cse154/19au/lectures/lec05-css-iii-more-layout/images/gatesnfences.png) Thoughts? .footnote[[gatesnfences.com](http://www.gatesnfences.com/)] --- # Review of tree construction .left-column[![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 150%](img/layout/colormeter.png)] --- # Naive version .left-column[ ![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 100%](img/layout/colormeter.png)] .right-column[
graph TD W(Window) --> M[Icon:Mag Window] W --> A[Slider:Aperture Size x y w h] W --> C[Menu:Choice x y w h] W --> I[Icon:Color x y w h] W --> T[Text:RGB x y w h] W --> La[Text:Label x y w h] class W green class M,A,C,I,T,La blue
] ??? Start talking here about meta data that maters, they know about x, y, w and h from doodle Ask them to think about what else you might want to know to position something? --- # Why do we need layout? .left-column[ ![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 100%](img/layout/colormeter.png) ] .right-column[ How can you center something? How can you lock it to an edge? How can you design layout that reacts (responds) well to turning your phone? Examples for web (from [CSE 154](https://courses.cs.washington.edu/courses/cse154/19au/lectures/lec05-css-iii-more-layout/index.html#/6)) - c0FFEE shop with [no layout](https://courses.cs.washington.edu/courses/cse154/19au/lectures/lec05-css-iii-more-layout/code/coffee-shop-solution/coffee-shop.html) - c0FFEE shop with [layout](https://courses.cs.washington.edu/courses/cse154/19au/lectures/lec05-css-iii-more-layout/code/coffee-shop-starter/coffee-shop.html) ] --- # User Interfaces on Android .left-column-half[ - Views - Base class for __all__ UI elements - Interactors (e.g buttons, labels, image views, etc) - ViewGroups - Encapsulates one or more views (e.g. Android Components, **Layouts**) - Can define specific **layout** properties We will talk about *Components* to include both layout components and interactors (Views) since these are not just interactors ] .right-column-half[
graph TD W(ViewGroup) --> V[ViewGroup] W --> V1[View] W --> V2[View] V --> V3[View] V --> V4[View] V --> V5[View] class W,V darkblue class V1,V2,V3,V4,V5 blue
] --- # Practice: Let's try to recreate this layout using containers and spacers .left-column[![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 150%](img/layout/colormeter.png)] -- .right-column[
graph TD W(Window) --> L(LeftSide:DisplayVert) W --> R(RightSide:SettingsVert) L --> Z[Space:Fixed] L --> M[Icon:Mag Window] L --> A[Slider:Aperture Size] L --> Y[Space:Stretchy] L --> C[Menu:Choice] R --> D(RGB DisplayHor) D --> V[Space:Fixed] D --> I[Icon:Color] D --> T[Text:RGB] D --> U[Space:Flexible] R --> Q[Text:Label] class W bluegreen class L,R,D green class Z,Y,V,U yellow class M,A,C,I,T,Q blue
] --- # Vertical Container Components .left-column[![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 150%](img/layout/colormeter.png)] .right-column[
graph TD W(Window) --> L(LeftSide:DisplayVert) W --> R(RightSide:SettingsVert) L --> Z[Space:Fixed] L --> M[Icon:Mag Window] L --> A[Slider:Aperture Size] L --> Y[Space:Stretchy] L --> C[Menu:Choice] R --> D(RGB DisplayHor) D --> V[Space:Fixed] D --> I[Icon:Color] D --> T[Text:RGB] D --> U[Space:Flexible] R --> Q[Text:Label] class L,R darkblue class W bluegreen class D green class Z,Y,V,U yellow class M,A,C,I,T,Q blue
Linear (1D) layout of components - Always layout in the same direction - Places its kids, in order, in that direction ] --- # Horizontal Container Components .left-column[![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 150%](img/layout/colormeter.png)] .right-column[
graph TD W(Window) --> L(LeftSide:DisplayVert) W --> R(RightSide:SettingsVert) L --> Z[Space:Fixed] L --> M[Icon:Mag Window] L --> A[Slider:Aperture Size] L --> Y[Space:Stretchy] L --> C[Menu:Choice] R --> D(RGB DisplayHor) D --> V[Space:Fixed] D --> I[Icon:Color] D --> T[Text:RGB] D --> U[Space:Flexible] R --> Q[Text:Label] class D darkblue class W bluegreen class L,R,D green class Z,Y,V,U yellow class M,A,C,I,T,Q blue
Same: Linear (1D) layout of components - Always layout in the same direction - Places its kids, in order, in that direction ] --- # Spacers .left-column[![:img Color Meter Mac App -- shows the RGB values for whatever pixel the cursor is over, 150%](img/layout/colormeter.png) ] .right-column[
graph TD W(Window) --> L(LeftSide:DisplayVert) W --> R(RightSide:SettingsVert) L --> Z[Space:Fixed] L --> M[Icon:Mag Window] L --> A[Slider:Aperture Size] L --> Y[Space:Stretchy] L --> C[Menu:Choice] R --> D(RGB DisplayHor) D --> V[Space:Fixed] D --> I[Icon:Color] D --> T[Text:RGB] D --> U[Space:Flexible] R --> Q[Text:Label] class Y,Z,V,U darkblue class W bluegreen class L,R,D green class Z,Y,V,U yellow class M,A,C,I,T,Q blue
- Work extra well with layout containers - We can add *Fixed Space* (struts) - Think of it like a strut in a building - They hold things a fixed distance apart - We can also add *Stretchy Space* (springs) - they push things apart as much as possible ] --- # Example (Layout Assignment) .left-column-half[ ![:img Picture of Pintrest, 50%](img/layout/pinterest-android.png) ] .right-column-half[ ![:img Picture of layout part 3, 40%](img/layout/pinterest-replica.png) ] ??? This is the kind of stuff we can do thanks to viewgroups --- # Example (Layout Assignment, part 3) .left-column-half[ I've highlighted things that are visible (as opposed to just doing layout work)
graph TD C[ViewGroup:ConstraintLayout] C --> Column1[ViewGroup:Column1] C --> Column2[ViewGroup:Column2] Column1 --> V1[View:Broccoli] Column1 --> V2[View:Seaweed] Column1 --> V3[...] Column2 --> V4[View:Soup] Column2 --> V5[...] class C,Column1,Column2 blue class V1,V2,V3,V4,V5 darkblue
] .right-column-half[ ![:img Picture of layout part 3, 40%](img/layout/pinterest-replica.png) ] ??? This is the kind of stuff we can do thanks to viewgroups --- # Android's runtime view of the same .left-column[ ![:img Picture of the andorid studio tools menu with Layout Inspector highlighted, 100%](img/layout/layout-inspector-menu.png) VERY IMPORANT debugging tool ] .right-column[ ![:img Picture of Part3 of the assignment running with the related interactor hierarchy at right, 70%](img/layout/part3-runtime.png) ] --- # Layout Assignment .left-column[ ![:img Part1: picture of food a button and a big textbox in a phone held vertically, 70%](img/layout/1_new_portrait.png) You can scroll this and the images are all equidistant. ] .right-column[ - Part 1 is about basic reactive layout using XML and constraints for a fixed number of images - Part 2 replicates this in code for a fixed number of images - Part 3 you create a *Layout Container* that can do a fancier layout, for an arbitrary number of images **Pintrest** style! - Part 4 you try to recreate a layout of your choice! ] --- # Brief Diversion: What is XML? - XML stands for eXtensible Markup Language - A superset of HTML - Tag names are surrounded by '<' and '>''s (Alligators or "wakkas") - Tags are generally in pairs such as `` `` or can be self closing `
` - Tags can have attributes such as `
content
` --- # Layout in Android .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard),100%](img/layout/layout-demo.png) ] .right-column-half[ This is Android's GUI layout editor Where's the interactor hierarchy here? It's the component tree! What are the leaf nodes? Do you see anything unusual? ] ??? point out the "space" --- # What is a spacer? .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard),100%](img/layout/layout-demo.png) ] .right-column-half[ What is a Space? - Works extra well with layout containers - We can add *struts* - Think of it like a strut in a building - They hold things a fixed distance apart - We can also add *springs* - they push things apart as much as possible ```xml
``` ] ??? see next slide! --- # Layout in Android .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard),100%](img/layout/layout-demo.png) ] .right-column-half[ In this case, they are in a `LinearLayout` - It always has a direction (horizontal or vertical) - And it places its kids, in order, in that direction, within its bounds Where is the linear layout on the screen? ] --- # Layout in Android .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard),100%](img/layout/layout-demo.png) ] .right-column-half[ In this case, they are in a `LinearLayout` - It always has a direction (horizontal or vertical) - And it places its kids, in order, in that direction, within its bounds Where is the linear layout on the screen? It's the box around 'Save and Discard' - We call this a *Layout Container* - Note: this is not visible in the actual GUI, it's a hidden interactor tree element ] --- # Layout in Android .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard),100%](img/layout/layout-demo.png) ] .right-column-half[ A Layout Container can - automate a lot of the layout tasks - make it much simpler to ensure reliable results - use these whenever they do the job - you will implement one for your assignment (you will be a *Library Extender*!) ] --- # Layout in Android Many layout and other attributes for components. You should explore! ![:img Picture of the whole android layout interface showing the possible components that can be added; the component tree (interactor hierarchy; and the attributes for the Save Button; which is selected, 90%](img/layout/design-view.png) ??? Talk about how there's many layout and other attributes for components that they should explore! --- # Layout in Android - The Layout XML View completely specifies what was in the GUI (and vice versa) - Get to it by clicking 'Text' (next to 'Design') .left-column[ ![:img Picture of the android layout interface showing the xml which completely specifies what was in the other image, 130%](img/layout/text-view.png) ] .right-column[ ```xml <-...->
<-...->
``` ] ??? What examples do we have here? - Layout container (linearlayout) - Spacer - springiness - struts - constraints --- # More about XML and Android .left-column[ ![:img Picture of the android ide file system with an xml file inside of res highlighted, 70%](img/layout/xml-files.png) ] .right-column[ Android has XML, where all sorts of static properties can be specified Every Android app has a `layout` directory and a `values` directory and several others. We'll use these in this assignment In XML you can set variables that we can access later in XML or code - In XML access a variable (such as `vMargin`) using `@(file name)/(value name)` , where the file name is a file somewhere in `res` and the value name is an xml value found in that file. i.e., for `vMargin`, you can use `"@dimen/vMargin"` - In code, you use `R.(file name).(value name)` ] --- # The importance of ID .left-column-half[ ```java *switch (item.getItemId()) { // Set window contents based on selected item. * case R.id.action_part_1: * setCurrentTabId(R.id.action_part_1); contents.addView(getLayoutInflater().inflate(R.layout.part1, null), PARAMS); // params here is a set of layout paramaters for this view return true; * case R.id.action_part_2: * setCurrentTabId(R.id.action_part_2); contents.addView(new Part2View(this, getImageStrings()), PARAMS); return true; //... } ``` ] .right-column-half[ - Set it in your layout XML when you create things! - Access it programmatically using `[Component].getId()` and `[Component].setID()`. - Access all Ids using `R.id.[ID]` - We use this to implement the tab navbar in Layout ![:img Picture of the android layout toolbar, 50%](img/layout/layouttoolbar.png) ] --- # Lot's to unpack here `PARAMS` is a class constant we added to `MainActivity` to hold the parameters for the layout: ```java *public static final RelativeLayout.LayoutParams PARAMS = * new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, * RelativeLayout.LayoutParams.MATCH_PARENT); ... switch (item.getItemId()) { // Set window contents based on selected item. case R.id.action_part_1: setCurrentTabId(R.id.action_part_1); * contents.addView(getLayoutInflater().inflate(R.layout.part1, null), PARAMS); return true; case R.id.action_part_2: setCurrentTabId(R.id.action_part_2); * contents.addView(new Part2View(this, getImageStrings()), PARAMS); return true; //... } ``` --- # PARAMS ```java public static final RelativeLayout.LayoutParams PARAMS = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT); ``` - There are lots of options for layout parameters, study the documentation! [Here](https://developer.android.com/reference/android/widget/RelativeLayout.LayoutParams) is the documentation for the `RelativeLayout` `LayoutParams` - Another common one is `WRAP_CONTENT` (that was the correct solution for your `TextView` in Doodle) - Note the re-usability if this variable in our `MainActivity` code! --- # Layout in Android The Layout XML View (completely specifies what was in the GUI) .left-column[ ![:img Picture of the android layout interface showing the xml which completely specifies what was in the other image, 130%](img/layout/text-view.png) ] .right-column[ We can use this programatically too! Called *Inflation* when we add an instance of `View` specified in XML ```java switch (item.getItemId()) { // Set window contents based on selected item. case R.id.action_part_1: setCurrentTabId(R.id.action_part_1); * contents.addView(getLayoutInflater().inflate(R.layout.part1, null), params); return true; case R.id.action_part_2: setCurrentTabId(R.id.action_part_2); contents.addView(new Part2View(this, getImageStrings()), params); return true; //... } ``` ] ??? - Need to clean up this slide... --- # Layout in Android .left-column-half[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard) and the constraints highlighted,90%](img/layout/constraint-editor.png) ] .right-column-half[ This assignment also uses **Constraints** (the `ConstraintLayout`) You can see little lines connecting the `textView` to its container and it's sibling (the `linearLayout`). - This specifies how it's attached (can change type by clicking on right) - If you were to change the interface (e.g. a different sized screen), it would stay attached and keep filling the space - All ends up in XML you can explore too ] --- # Layout in Android .left-column-half[ ![:img A simple layout on an android phone instead of a watch with a textview and two buttons (save and discard),100%](img/layout/explore-devices.png) ] .right-column-half[ You can test this: modify the aspect ratio of your display, and flip it to horizontal to test things ] ??? Demonstration: consider demoing this interface live PRINT THIS LIST - Show dragging things to create layout - Show different size and orientation phones - Show editing attributes - Show clicking on constraints in box to change type - Show simple interface hierarchy - Show simplifying xml - Show changing button names/ids --- # What are Constraints? .left-column[ ![:img A simple layout on an android watch with a textview and two buttons (save and discard) and the constraints highlighted,110%](img/layout/watch3.png)] .right-column[ - Very general - Can reproduce most other things - Can operate on multiple axes - Can enhance other layout options What do you think this does? `app:layout_constraintBottom_toTopOf="@+id/linearLayout"` And this? `app:layout_constraintEnd_toEndOf="parent"` We also use `Start_tStartOf` and 'Top_toTopOf` to create this (note: full xml spec if you scroll down) ```java
lp.setMargins((int)(1*density),0,0,0); ``` ] --- .left-column[ ## Constraints in Android ![:img picture of attributes window showing controls for constraint-based layout including five types of elements, 100%](img/layout/constraints.png)] .right-column[ [Docs](https://developer.android.com/training/constraint-layout/): limited set of constraints - 1 Size ratio - 2 Delete constraint (not a constraint, just removes them) - 3 Height/width mode (3 main types): - Wrap constraint ![:img wrap symbol >>>, 5%](img/layout/wrap.png) - Fixed size ![:img fixed symbol I--I, 5%](img/layout/fixed.png) - Match Constraint ![:img match symbol IvvvI, 5%](img/layout/match.png) - 4 Margins - 5 Constraint bias (essentially weights on competing constraints) Range of attachment options (e.g. button sides, corners) Worth getting to know additional abstractions (groups; guidelines; barriers; chains) ] ??? -bias lets us create something that is 2-3 of the way over rather than centered go back to android to demo again --- # Powerful option Can do everything we can do with springs, struts, and linear layouts Declare relationships (.red[what] should be true) System automatically maintains relationships under change (.red[how]) --- # Powerful option Can do everything we can do with springs, struts, and linear layouts Declare relationships (what should be true) - This should be centered in that - This should be 12 pixels to the right of that - Parent should be 5 pixels larger than child System automatically maintains relationships under change (how) --- # Powerful option Can do everything we can do with springs, struts, and linear layouts Declare relationships (what should be true) System automatically maintains relationships under change (how) Too good to be true? - Unsolvable for arbitrary things - Works really well for a limited set ??? a good set for ui programming xx need to make sure I know why it is hard for arbitrary things --- # Note that these are one-way constraints You can change the right side, and it will update the left side (not the reverse) Can be very inefficient .jax[$$O(2^n)$$] But highly efficient incremental update algorithms exist ??? Only have to update things that might change Hudson's work on this was seminal can have a DAG but not a cycle (thus, a tree) hard to guard against cycles --- # Layout Assignment .left-column[ Part 1 is about basic reactive layout using XML and constraints ![:img Part1: diagram of images evenly spaced stacked vertically, 70%](img/layout/part1-diagram.png) ] .right-column[ We will use constraints for the left/right/top/bottom of each image `scaleType`, `width` and `height` will be provided for you There are also things we specify without constraints: margins, for example. - Android best practice is to use a variable for this - How do we do that in XML? ] --- # Layout Assignment .left-column[ ![:img Part1: diagram of images evenly spaced stacked vertically, 70%](img/layout/part1-diagram.png) ] .right-column[ - Layout assignment - Part 1 is about basic reactive layout using XML and constraints - Part 2 asks you to reproduce this in code - Not all that different from creating views in Doodle - What are the key steps here? ] ??? instantiate add to the hierarchy Just now we will also add layout containers --- # Layout Assignment .left-column[ ![:img Part1: diagram of images evenly spaced stacked vertically, 70%](img/layout/part1-diagram.png) ] .right-column[ - Layout assignment - Part 1 is about basic reactive layout using XML and constraints - Part 2 asks you to reproduce this in code - Not all that different from creating views in Doodle - What are the key steps here? - instantiate (create an interactor) - add to the hierarchy - just now we will also add layout containers ] --- # Three ways to create Interactors Specify elements in WYSIWYG editor, which will automatically create and initialize the objects Instantiate UI classes at runtime. We did it in Doodle at runtime! --- # Runtime Instantiation *FROM XML* This is called *Inflation* and you should use it in your assignment!! (why?) To do it you need to `import [package].R;` Then if you know the name of something, you can access it, e.g. ```java import android.view.ViewGroup.LayoutParams; import cse340.layout.R; Button okButton = new Button(this); okButton.setText("OK"); LinearLayout layout = (LinearLayout)findViewById(R.id.linearLayout); LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); layout.addView(okButton,lp); ``` ??? could push this off, doesn't look like we use it after all in layout. But they do need to access R I think. add this if time ```java // you can change the ID ... in XML or in code for (int i = 0; i