as2: Layout
Last revised: 5-April, 2022- Part 1-5 Wed 6-Apr
- Part 1-2 Checkpoint 10:00 pm, Thur 14-Apr
- Part 3-4 (Code) & Part 5 (Reflection) 10:00pm, Thur 21-Apr
HCI Goals:
- Make use of interactor hierarchy
- Use constraints to create responsive layouts
- Make use of complex built-in layouts
- Implement reusable layouts
- Understand how scrolling works
- Understand how sizes influence layout
Android Goals:
- Create a generalizable, reusable layout for any number of images
- Understand Android layout GUI and XML
- Familiarize with Android programmatic layout API
- Understand Android constraints implementation
- Handle portrait and landscape orientation correctly
- Handle fixed and variable sized container views
- Learn about Inflators
- Turn-in links
- Assignment Description
- Introduction to Parts 1 and 2
- Part 3
- Part 4
- Part 5 (Reflection)
- Development Strategies
- Debugging tips and tricks
- Turn in
- Grading (50pts)
Turn-in links
- Part 1-2 Code: Upload and mark the code in the Layout 1-2 Ed Lesson
- Part 3-4 Code: Upload and mark the code in the Layout 3-4 Ed Lesson
- Part 5 Reflection: Write your reflection and turn it into Gradescope
Assignment Description
This is the assignment spec for our Layout module of the class. Scroll down to the development strategies sections for some tips curated from past students!
An important note: Part 1-2 and Part 3-5 are NOT equivalent in difficulty. Part 1-2 will take significantly less time than Parts 3-5. Once you have completed part 1-2, turn it in and continue to work on the rest of the assignment. The checkpoint will help you discover early any misconceptions. Clearing up those misconceptions early will help with the balance of development cycle to ensure your code is working correctly.
Finally, note that all dimensions in all parts of this assignment should be specified in density independent pixels (i.e. dp instead of px).
Inheritance Hierarchy
Like Doodle, our MainActivity
inherits from a TabActivity
which we have created to
switch between each of the parts of this assignment. However instead of switching between
Activity
objects, we’re switching between View
objects. Part2View
and Part3View
inherit
from a ScrollView
, and Part4View
inherits from a ConstraintLayout
to allow for the most
flexibility in your creative portion of this assignment.
Introduction to Parts 1 and 2
For parts 1 and 2, you will be building the same layout twice. It must show at least five images,
be scrollable, and look equally nice horizontally and vertically. Additionally, you must
use constraints to achieve this, using the ConstraintLayout
we provide in part1.xml
.
part1.xml
can be found in the res/layout
directory in Android Studio once the layout
project
has been opened.
The results should look like this:
For part 1, you will use Android Studio’s built-in layout editor to create the desired layout, using a combination of XML and the GUI.
For part 2, you will create the same layout programatically, using Java code to construct view objects and add them to our activity. In this way you will demonstrate how to make a generalizable layout class that can be reused for an arbitrary number of images.
This video shows parts 1 and 2 in action:
A (slightly simplified) view of the interactor hierarchy for parts 1 and 2 is shown below.
Two notes about the interactor diagrams in this specification:
- That the important parts are shown, there are some levels in the tree we have omitted for brevity.
- The interactors colored in green have been provided for you, you are only to implement the interactors colored blue.
We can represent this same interactor hierarchy visually in a Layout Wireframe. An
example of a Layout Wireframe for Part 1 is shown below which details the visual
nesting of the interactors, margin spacing between the interactors. Layout Wireframe
diagrams are a design tool to help you visualize how your app will function
programatically. For instance, in this sample, we can see that you will only be
adding images inside the ConstraintLayout
. (Note: this layout diagram should
be more detailed and also include labels for the ImageView
and other objects).
This Layout Wireframe highlights that you will only be configuring the ImageViews
as they relate to the ConstraintLayout
(shown in blue). Note that this Layout Wireframe
is simplified representation of what you would see in the Layout Inspector.
You will be drawing Layout Wireframes for Part 4 of assginment as well
in other parts of this course. The Layout Wireframes you produced must be more
complex than what you see here. You will be expected to explicitly label each
View
, layout container, spacing,
etc, and as well as specify any relevant information about orientation (such as
Vertical vs Horizontal LinearLayout
).
Related Info
You may find the following link helpful when working with constraint layouts: “Building a Responsive UI with Constraint Layout” (pay particular attention to the Set size as a ratio section).
Further details on Part 1
Tasks:
- Use the tools provided by Android Studio to build a layout that vertically stacks images.
When it comes to layout, working directly with XML can be a pain, especially when there are several attributes to keep track of on each element. Luckily, Android Studio provides a visual editor that you can use to build your app layout.
For part1.xml
, you will accomplish the following:
- Familiarize yourself with how to reference images in res/drawable.
- Use the Visual and XML editor to construct a single, scrollable column of images.
- You must place a
vMargin
gap between images and their container, as well as between consecutive images. You must also ensure that the bottom image does have avMargin
space between it and its parent’s bottom.vMargin
is defined inres/values/dimens.xml
- Your layout must have enough images that you need to scroll (use
animal_0
throughanimal_4
) - Each image must be scaled so it fits horizontally and is centered while maintaining its aspect
ratio. This requires you to set some attributes specific to
ImageView
which are mentioned in the ImageView Documentation.- It may be helpful to also look at how the
ImageView
objects are loaded inMainActivity#getImages
and what methods are called on theImageView
after it is created. - It is important to note that
ImageView
objects that are created programatically has ascaleType
ofFIT_CENTER
, which is not true ofImageView
objects that are inflated source).
- It may be helpful to also look at how the
- You must use constraints to ensure that an image is adjacent to the previous image
(
Top_toBottomOf
) and that its left and right side are constrained to the parent container.
Related Info
- ConstraintLayout
- Linear Layouts
- ImageView
- ViewGroup.LayoutParams#MATCH_PARENT
- ViewGroup.LayoutParams#WRAP_CONTENT
- A guide for Android ImageView ScaleType and adjustViewBounds
Further details on Part 2
The Part2View
starter code can be found in the cse340.layout
directory in Android Studio.
In Part2View
we have set up the basic scaffolding necessary to complete the given layout. For this section you will be instantiating the view objects from Part 1 programmatically.
Tasks:
- Start by looking at how we are creating the
Part2View
inMainActivity
. Here you will see that we are calling thegetImages
method. You are not to change anything in this file or method (in fact we won’t accept it if you do), but it is helpful to read through the code to see what is being programatically set on eachImageView
that is create. - For Part 2 you must programmatically accomplish the same layout requirements from Part 1. The
desired layout can be accomplished by setting layout parameters on the
View
objects in Java. Additionally, yourPart2View
constructor should be able to support an arbitrary number of images, not just the ones specified in an XML file.
It may be useful to view the interactor hierarchy using Layout Inspector when Part 1 is running to understand how to structure the views you are creating programatically in Part 2.
Reminder: Turn in your completed Part 1 and 2 to the appropriate Ed lesson for your check point. The course staff will give quick feedback about the correctness of part 1-2 while you are completing the balance of your assignment.
Part 3
The Part3View
starter code can be found in the cse340.layout
directory in Android Studio. We will create a custom Layout in Part3 that can organize an arbitrary series of Views into a Pinterest-like layout. Pinterest is a great example of a high-profile app that can be built with relatively simple layout instructions. For instance, one could imagine breaking the layout into two large vertical columns, then assigning various elements to each one. You will also need to ensure the columns never differ by more than the height (in dp) of one image.
To determine which column a photo should go in, we will use “pinterest” ordering. You must track the height of the images in each column and add the next image to the shorter column (or the left column if equal).
Note that the aspect ratio of images may vary (they may have an arbitrary width and height. For this reason, you will need to figure out the image’s height once it is scaled to fit within the width of its column.
To do this, you will need to find out the displayed (or measured) height of the image. This requires that you get the measured width of a column (with the image added), then use that to measure the height of each image. It will help to take a look at How Android Draws Views and View#Measure(int, int) for this.
It is important to understand that two photos with different resolutions but the same aspect ratio (width to height ratio) will both affect the column height identically because they will be scaled to have the same size on-screen.
Keep in mind that similar to Part 1 and Part 2, your Part 3 layout should be responsive to
device orientation. When rotated your layout should maintain the proper positioning
(vMargin
s, spacing, and aspect ratios should remain the same while images scale to fill
the extra space.)
Our Pinterest style layout will be achieved both by using Layout Inflation (using a
LayoutInflater
with a valid XML file). A
LayoutInflater
allows us to accept a valid XML file specifying part of an interactor hierarchy and
convert it into a View object that can be added to the interactor hierarchy you are
constructing. This can be seen in practice in the R.id.action_part_1
case in
MainActivity#onCreate(Bundle)
, which uses one of the four overloaded
LayoutInflater#inflate
methods.
Note that there is a difference between Part1
and Part3
in how we get the LayoutInflater
.
We inflate Part1
in MainActivity#onCreate(Bundle)
, and because we’re in a subclass of Activity
we can call Activity#getLayoutInflater()
. This is not the case in Part3View
, a subclass of
View
which does not have that method available. Instead we need to get the LayoutInflator
from
the class “factory” LayoutInflator#from(Context)
. See the
documentation
for more details.
The XML for your layout can be built by hand writing the code or by using the
XML/visual editor which is often easier when building static app layouts. Once
the XML has been written, we can use an inflater in our .java
code convert
the XML into an object before programmatically appending it to our current app layout.
The interactor hierarchy for Part 3 is shown below. The elements marked in light
green must be created using inflation (and the part3_grid.xml
file must do this).
The elements shown in blue must be created programmatically. Note that we
are using LinearLayout
to hold the images (not ConstraintLayout
as in
Part 1 and 2).
Tasks:
- Before getting started on this section, try constructing a LayoutInflater and passing in your
part1.xml
file. - Once you are comfortable with inflation, use inflation to make use of the
ConstraintLayout
we have provided for you in thepart3_grid.xml
file. - Modify the
part3_grid.xml
file per the instructions in the comments to create the two columns. - Try modifying the
part3_grid.xml
by hand to inflate with some temporary images in a Pinterest style layout to make sure you know what layout parameters you should be using when you add images programatically. - Then remove those temporary images and programmatically create
ImageView
objects based on the information passed in:- Add each image to the bottom of one of the two columns.
- Which column an image is added to will depend on the current length of both columns (the image will be added to the bottom of the currently shorter column).
- Each image must be
vMargin
from the next image vertically and from the top of the column if it is the first image in that column. - There must be a
vMargin
gap between the left image and the left side of the screen, between the right image and the right side of the screen, and between the two columns. The center of thevMargin
gap between the two columns must be in the exact center of the screen. All images must be horizontally scaled to to be wide enough to meet these margins exactly. - There must be a
vMargin
gap after the last image of each column. This creates at least avMargin
gap between the last image and the bottom navigation bar. - The heights of the images must be scaled proportionally based on the constrained width.
- Write code in
onMeasure()
to evenly distributes ImageViews between a given set of columns based on the scaled height they will be on screen, not the dimensions from the drawable resource.
Your starter code for Part 3 has detailed comments to guide you in how to implement
onMeasure
. One tricky bit: you may find that the ImageView
objects do not
initially have a measurement. It will help to recall that with the implementation
of Android’s Measure-Layout-Draw algorithm, you can force a parent view to measure itself, which will in turn force the children of that view to measure themselves.
Related Info
- LayoutInflater
- How Android Draws Views
- View#measure()
- View.MeasureSpec#makeMeasureSpec()
- Measure Layout Draw
Part 4
For Part 4 you are to re-create an interface from another popular app such as Twitter, Facebook, Instagram, etc. Most commercial products, however, are very complicated, so this is your chance to be creative in the design and implement your own version of the app. The goal is for you to synthesize what you have learned in class as well as explore other features (such as other types of Common Layouts) that we have not covered in class.
Your layout must meet the following requirements:
- Your creative part 4 MUST be more complicated than the simple linear layouts in part 1 and must be substantively different from the Pinterest layout in Part 3, and the image that is given as part of our reflection in Part 5.
- Your layout must be scrollable and contain more items than can fit on one screen.
- You must both use inflation as well as programatic methods (i.e. creating
and adding views) to add your
View
objects into your interactor hierarchy.- Repeated groups of items should be encapsulated in a view group that can be inflated programatically.
- Images should not contain text in lieu of creating
ImageView
andTextView
objects separately. For instance, if you have an image with a caption, the image and the caption text should be two separate interactors, the caption should not be part of the image file.
- Your layout must be responsive to device orientation. If the user rotates their device, then your application must adjust to fit the new orientation. If the app you are emulating does not have a landscape mode, you must make an educated guess as to what a landscape mode version of this app might look like.
- Your version of the known interface may be simplified:
- You do not need to implement all screens of the interface, one screen that demonstrates an interface that includes an interesting layout of text an images should suffice.
- Your version of the interface should be sufficiently similar to the one you’re emulating. Don’t leave out things like icons & text.
Note: Unfortunately, you will not be able to implement a “sticky” top or bottom bar for your custom layout. This is due to a limitation with the implementation of the scrolling behavior. We will not penalize you for leaving the “sticky” aspect of these bars out.
The Part4View.java
starter code can be found in the cse340.layout
directory.
It extends from ConstraintLayout
to give you maximum flexibility to allow
you to add anything you need to achieve your desired design.
You may also note, that while the constructor has vMargin
as a parameter,
you are not required to use our vMargin
value.
You may use the same images that are used in Part 3. If you wish to do so, you
should simply call the appropriate method in MainActivity.java
. There is a
note on how to do this in the Part4View
constuctor.
To keep your code organized you may wish to group some views together into
a new View
. If you choose to do this, we will accept an additional java
file MyViewHolder.java
and an extra layout, myviewholder.xml
.
And finally, recall that there are four methods for inflating an XML file - research which one is appropriate for your creative layout implementation.
Tasks:
- Before you start, sketch the interface you’ve chosen to mock up as a Layout Wireframe on a
piece of paper or using a tablet pen. This sketch will be turned in as part of your reflection
in Part 5.
- Your Layout Wireframe should be fairly detailed in describing what interactors you plan to use. For instance, specify where you are using spacers, or whether a Layout is horizontal or vertical.
- Also draw out the Interactor Hierarchy for the interface. Your Interactor Hierarchy may be done with a computer program.
- Using XML and programatic means, create your version of this interface.
- Make sure that you create a
part4.xml
file and add/commit/push it to your GitLab repository - Similarly, if you use your own pictures for Part 4, ensure they have also been committed and pushed to your Gitlab repo.
Helpful Links
Past students have found the following links helpful in designing and implementing Part 4:
- Miro or Figma are good tools for creating wireframes and interactor hierarchies.
- Material Design Icons is a resource images to work with.
Part 5 (Reflection)
For this part, you will submit your reflection on this assignment to Gradescope. Create a MS Word, Google or other type of document and copy the following questions (in italics below) into that document. Add your responses below each question. You can have more than one answer per page, but if you can, please try to avoid page breaks in the middle of a question. Insert page breaks between questions as needed.
-
Diagrams and images
- The Layout Wireframe you drew for Part 4.
- The interactor hierarchy you drew for Part 4. (Do not turn in a screen shot of the layout inspector for this).
- A screenshot of the interface you are emulating, in both portrait and landscape mode. You must explicitly specify if the app you are emulating does not have a landscape mode.
- A screen shot of your final interface in both portrait and landscape mode.
- For every interface there are generally multiple ways of laying it out, particularly if the interface is a complicated one. Reflect on your design and implementation of Part 4. What other ways you could emulate the same interface using different ViewGroups/Layouts. What would be the benefits or drawbacks to using these other Layouts?
-
The image below is a simplified screen capture from a music playing app.
- Draw a Layout Wireframe for the portion of the app shown. Your Wireframe should contain a minimum of four layouts. It may help to check out the Common Layouts.
- Briefly justify the reason why you chose the layouts you did in part a).
- Draw the interactor hierarchy for the portion of the screen shown below.
- Responsive design is when you create an application that “responds” to dynamic changes in the screen size or orientation of the device. Why are responsive designs important in user interfaces, software development and software engineering, as well as real life applications? Think beyond just an app on a screen…
- This class is part theory, part implementation. As such, lecture and section may not have provided you all of the information necessary to complete the layout program. How did you approach the independent learning required to complete this assignment? List at least one resource you used in your learning that would recommend to a friend taking this class in the future.
- Acknowledgements: Cite anything (website or other resource) or anyone that assisted you in creating your solution to this assignment. Remember to include all online resources (other than information learned in lecture or section and android documentation) such as Stack Overflow, other blogs, students in this class, or TAs and instructors who helped you during OH.
A screenshot of a music playing app.
Development Strategies
- You may run into issues when rotating the device. Note, when rotating the emulated device or your personal Android device, that the layout must adjust accordingly. You do not need to readjust the layout of your images when rotating the device, as this must remain the same.
These buttons will allow you to rotate the emulated device clockwise/counter-clockwise.
- On average, students in 20wi and 20sp said they spent about 12 - 16 hours on this assignment. However, it has been modified significantly since then. Recall that Part 1-2 is significantly easier than Part 3-4, so resist the temptation to do only the requirements for Part 1-2 before the checkpoint, start Part 3-4 early! Part 3-4 may be one of the more time-consuming assignments of the quarter.
-
Read through the starter code!! Particularly make sure you’re reading through
MainActivity.java
as that will help you to understand how theView
s are being created AND how the images are being loaded into memory inMainActivity#getImages
- When dealing with the Android documentation: ask as many questions as necessary!
The android documentation can be painful to read through, as there are many potential
options to choose from. If you need any help parsing it, feel free to ask anyone on the
course staff for advice. Additionally, we suggest that you read through the following
resources as you develop your apps, to better understand the tools you are utilizing
(these are referenced in their respective parts as well):
- An explanation of the ImageView ScaleType attribute (Part 1)
- Building a Responsive UI with Constraint Layout (Part 3) Note the “Set Size as a ratio” section here
- What’s new in Constraint Layout 1.1.0 (Part 4)
- Adjusting the view size
- A guide for Android ImageView ScaleType and adjustViewBounds
Code quality and commenting your code
We expect that you will maintain the same Code Quality and Commenting standards as you did with our Doodle assignment. For details please see those sections.
Debugging tips and tricks
- Recall that you can use the Layout Inspector to see where your views are placed in the parent.
The Layout Inspector is can be found under
View -> Tool Windows -> Layout Inspector
. - If your application stops running (the device displays an alert that says
“
has stopped"), you likely have a serious runtime error. Make sure to look at the _Run_ tab at the bottom of the screen. More information on runtime crashes is available through [developer.android.com](https://developer.android.com/topic/performance/vitals/crash) . - Your application may crash while inflating if there is a problem with your
.xml
file. - Logging output is especially useful for testing the functionality of sections of code such as
Layout#MainActivity#OnCreate
and other methods. Much likeSystem.out.print
in Java, Android provides its own class for producing output:Log
. We suggest that you useLog.i
and create your own custom tag so that you can filter the output for the information you want. Below is an example of how to use theLog.i
function.
private static final String TAG = "Layout";
Log.i(TAG, "Hello world!");
To make full use of Logcat, make sure to configure the priority level (in this case, “Info”) and use the correct tag (in this case, “Layout”). It’s also good to check that you have the correct device/emulator selected.
Note: Remember to take your Log.i
debugging calls out of your code before turning it in.
Related Info
Turn in
Code Submission Instructions
We will test layout on emulators with different screen sizes. Please use constraints correctly. Don’t just try to match pixels in our sample screenshots.
You will turn in your source code files to the appropriate Ed Lessons for Part 1-2 and then for Part 3-4.
We are allowing you to turn in Part 1-2 early for a checkpoint to see how closely you match our tests. You will get 1 point for turning in code that compiles and passes up to half of the tests. If you pass more than half the tests, we will award you 2 points.
Make sure you only edited the following files for submission:
- Part2View.java
─ Part3View.java
─ Part4View.java
- res/drawable
- res/layout/part1.xml
- res/layout/part3_grid.xml
- res/values/strings.xml
- res/values/dimens.xml
Note: While you can edit the above files, please do not remove any of the existing drawables, Strings, or dimensions from them.
If you wish, you may also include the following extra files:
─ MyViewHolder.java
- res/layout/myviewholder.xml
- res/layout/part4.xml
- assets/part4.csv
Do not edit any of the other files that we have given you, do not delete any of the images in the
res/drawable
folder, and do not delete any existing strings in res/values/strings.xml
(you may add bitmaps and strings of course.)
If you add your own images or other files for Part 4, please make sure to add, commit, and push them to your repository in the appropriate directories before turning in your assignment. If your images are not there, your custom layout will not work for others and you will NOT get credit for the work you did.
Note: Large images can be problematic both for running your app and for committing to your gitlab repository (there are size limit imposed on both Ed and Allen School resources). If you choose to add your own images, add at most 10MB of data (you will not be able to turn in your assignment in if it is larger than that). One solution is to resize your high resolution images before using them in your creative application.
Reflection submission
The reflection will be turned in to Gradescope.
Grading (50pts)
The Layout assignment will be out of 50 points and will roughly (subject to small adjustments) be distributed as:
Part 1-2 checkpoint (2pts) Note: this MUST be turned in on time to receive points. No late assignment for part 1-2 will be accepted.
- Turned in and compiles: 1 pt
- Passed >1/2 of tests: 1 pt
Final checkpoint (48 pts)
- Part 3-4 code (28 pts)
- Part 1 (6 pts) has correct layout (checking parameters margins and so on); and works in landscape mode; doesn’t overuse constraints (i.e. not too many)
- Part 2 (7 pts) has correct layout (as above); works in landscape mode; and can handle multiple images
- Part 3 (9 pts) has correct layout (checking parameters margins and so on); has correct Pinterest ordering; properly uses inflation
- Part 4 (5 pts) including:
- Is sufficiently different from Part 1-3 (and at least as complex)
- Works in portrait and landscape
- Code uses both XML and programmatic methods for creating view
- Overall code quality (1pt)
- Reflection (20 pts)
- Layout Wireframe, Interactor Hierarchy, and screenshots of part 4 (4 pts total)
- Reflection questions 2, 4, 5 will be worth 3 points each (9 pts total)
- Reflection question 3 (6 pts)
- Acknowledgements (1pt)
IDE Errors/Warnings you can ignore
Note: DO NOT assume that because an error/warning can be ignored for this assignment, it can be ignored for all assignments. ALWAYS check the spec for each assignment before deciding what is OK to ignore.
-
Button
- Hardcoded Strings
-
TextView
- Hardcoded Strings