Android Programming with Kotlin for Beginners
上QQ阅读APP看书,第一时间看更新

Building a UI with CardView and ScrollView

Create a new project in the usual way. Name the project CardView Layout and choose the Empty Activity project template. Leave all the rest of the settings the same as all the previous projects.

To be able to edit our theme and properly test the result, we need to generate our layout file and edit the Kotlin code to display it by calling the setContentView function from the onCreate function. We will design our CardView masterpiece inside a ScrollView layout, which, as the name suggests, allows the user to scroll through the content of the layout.

Right-click the layout folder and select New. Notice that there is an option for Layout resource file. Select Layout resource file and you will see the New Resource File dialog window.

In the File name field, enter main_layout. The name is arbitrary, but this layout is going to be our main layout, so the name makes that plain.

Notice that it is set to LinearLayout as the Root element option. Change it to ScrollView. This layout type appears to work just like LinearLayout, except that, when there is too much content to display on screen, it will allow the user to scroll the content by swiping with their finger.

Click the OK button and Android Studio will generate a new ScrollView layout in an XML file called main_layout and place it in the layout folder ready for us to build our CardView-based UI.

You can see our new file in this next screenshot:

Android Studio will also open the UI designer ready for action.

Setting the view with Kotlin code

As we have done previously, we will now load the main_layout.xml file as the layout for our app by calling the setContentView function in the MainActivity.kt file.

Select the MainActivity.kt tab. In the unlikely event the tab isn't there by default, you can find it in the project explorer under app/java/your_package_name, where your_package_name is equal to the package name that you chose when you created the project.

Amend the code in the onCreate function to look exactly like this next code. I have highlighted the line that you need to add:

override fun onCreate(savedInstanceState: Bundle?) {
   super.onCreate(savedInstanceState)
   setContentView(R.layout.main_layout);
}

You could now run the app, but there is nothing to see except an empty ScrollView layout.

Adding image resources

We are going to need some images for this project. This is so we can demonstrate how to add them into the project (this section) and neatly display and format them in a CardView layout (next section).

It doesn't really matter where you get your images from. It is the practical hands-on experience that is the purpose of this exercise. To avoid copyright and royalty issues, I am going to use some book images from the Packt Publishing website. This also makes it easy for me to provide you with all the resources you need to complete the project should you not want to go to the bother of acquiring your own images. Feel free to swap the images in the Chapter05/CardViewLayout/res/drawable folder.

There are three images: image_1.png, image_2.png, and image_3.png. To add them to the project, follow these steps.

  1. Find the image files using your operating system's file explorer.
  2. Highlight them all and press Ctrl + C to copy them.
  3. In the Android Studio project explorer, select the res/drawable folder by left-clicking it.
  4. Right-click the drawable folder and select Paste.
  5. In the pop-up window that asks you to Choose Destination Directory, click OK to accept the default destination, which is the drawable folder.
  6. Click OK again to Copy Specified Files.

You should now be able to see your images in the drawable folder along with a couple of other files that Android Studio placed there when the project was created, as shown in this next screenshot:

Before we move on to CardView, let's design what we will put inside them.

Creating the content for the cards

The next thing we need to do is create the content for our cards. It makes sense to separate the content from the layout. What we will do is create three separate layouts, called card_contents_1, card_contents_2, and card_contents_3. They will each contain a LinearLayout, which will contain the actual image and text.

Let's create three more layouts with LinearLayout at their root:

  1. Right-click the layout folder and select New layout resource file.
  2. Name the file card_contents_1 and make sure that LinearLayout is selected as the Root element
  3. Click OK to add the file to the layout folder
  4. Repeat steps one through three two more times, changing the filename each time to card_contents_2 and then card_contents_3

Now, select the card_contents_1.xml tab and make sure you are in design view. We will drag and drop some elements to the layout to get the basic structure and then we will add some sp, dp, and gravity attributes to make them look nice:

  1. Drag a TextView widget on to the top of the layout.
  2. Drag an ImageView widget on to the layout below TextView widget.
  3. In the Resources pop-up window, select Project | image_1 and then click OK.
  4. Drag another two TextView widgets below the image.
  5. This is how your layout should now appear:

Now, let's use some material design guidelines to make the layout look more appealing.

Tip

It is possible that, as you proceed through these modifications, the UI elements on the bottom of the layout might disappear from the bottom of the design view. If this happens to you, remember you can always select any UI element from the Component Tree window underneath the palette. Or, refer to the next tip.

Another way of minimizing the problem is to use a bigger screen, as explained in the following instructions:

Tip

I changed the default device for the design view to Pixel 2 XL to create the previous screenshot. I will leave this setting for the rest of the book unless I specifically mention that I am changing it. It allows a few more pixels on the layout and means this layout is easier to complete. If you want to do the same, look at the menu bar above the design view, click the device dropdown, and choose your design view device, as shown in the following screenshot:

  1. Set the textSize attribute for the TextView widget at the top to 24sp.
  2. Set the Layout_Margin | all attribute to 16dp.
  3. Set the text attribute to Learning Java by Building Android Games (or whatever title suits your image).
  4. On the ImageView, set layout_width and layout_height to wrap_content.
  5. On the ImageView, set layout_gravity to center_horizontal.
  6. On the TextView beneath the ImageView, set textSize to 16sp.
  7. On the same TextView, set Layout_Margin | all to 16dp.
  8. On the same TextView, set the text attribute to Learn Java and Android from scratch by building 6 playable games (or something that describes your image).
  9. On the bottom TextView, change the text attribute to BUY NOW.
  10. On the same TextView, set Layout_Margin | all to 16dp.
  11. On the same TextView, set the textSize attribute to 24sp.
  12. On the same TextView, set the textColor attribute to @color/colorAccent.
  13. On the LinearLayout holding all the other elements, set padding to 15dp. Note that it is easiest to select LinearLayout from the Component Tree window.
  14. At this point, your layout will look very similar to the following screenshot:

Now, lay out the other two files (card_contents_2 and card_contents_3) with the exact same dimensions and colors. When you get the Resources popup to choose an image, use image_2 and image_3 respectively. Also, change all the text attributes on the first two TextView elements so that the titles and descriptions are unique. The titles and descriptions don't really matter; it is layout and appearance that we are learning about.

Tip

Note that all the sizes and colors were derived from the material design website at https://material.io/design/introduction, and the Android specific UI guideline at https://developer.android.com/guide/topics/ui/look-and-feel. It is well worth studying alongside this book, or soon after you complete it.

We can now move on to CardView.

Defining dimensions for CardView

Right-click the values folder and select New | Values resource file. In the New Resource File pop-up window, name the file dimens.xml (short for dimensions) and click OK. We will use this file to create some common values that our CardView object will use by referring to them.

To achieve this, we will edit the XML directly. Edit the dimens.xml file to be the same as the following code:

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <dimen name="card_corner_radius">16dp</dimen>
    <dimen name="card_margin">10dp</dimen>
</resources>

Be sure to make it exactly the same because a small omission or mistake could cause an error and prevent the project from working.

We have defined two resources, the first called card_corner_radius, with a value of 16dp, and the second called card_margin, with a value of 10dp.

We will refer to these resources in the main_layout file and use them to consistently configure our three CardView elements.

Adding CardView to our layout

Switch to the main_layout.xml tab and make sure you are in the design view. You probably recall that we are now working with a ScrollView that will scroll the content of our app, rather like a web browser scrolls the content of a web page that doesn't fit on one screen.

ScrollView has a limitation – it can only have one direct child layout. We want it to contain three CardView elements.

To overcome this problem, drag a LinearLayout from the Layouts category of the palette. Be sure to pick LinearLayout (vertical), as represented by this icon in the palette:

We will add our three CardView objects inside LinearLayout and then the whole thing will scroll nice and smoothly without any errors.

CardView can be found in the Containers category of the palette, so switch to that and locate CardView.

Drag a CardView object onto the LinearLayout on the design and you will get a pop-up message in Android Studio. This is the message pictured here:

Click the OK button, and Android Studio will do some work behind the scenes and add the necessary parts to the project. Android Studio has added some more classes to the project, specifically, classes that provide CardView features to older versions of Android that wouldn't otherwise have them.

You should now have a CardView object on the design. Until there is some content in it, the CardView object is only easily visible in the Component Tree window.

Select the CardView object via the Component Tree window and configure the following attributes:

  • Set layout_width to wrap_content
  • Set layout_gravity to center
  • Set Layout_Margin | all to @dimens/card_margin
  • Set cardCornerRadius to @dimens/card_corner_radius
  • Set cardEleveation to 2dp

Now, switch to the Text tab and you will find you have something very similar to this next code:

<androidx.cardview.widget.CardView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center"
   android:layout_margin="@dimen/card_margin"
   app:cardCornerRadius="@dimen/card_corner_radius"
   app:cardElevation="2dp" />

The previous code listing only shows the code for the CardView object.

The current problem is that our CardView object is empty. Let's fix that by adding the content of card_contents_1.xml. Here is how to do it.

Including layout files inside another layout

We need to edit the code very slightly, and here is why. We need to add an include element to the code. The include element is the code that will insert the content from the card_contents_1.xml layout. The problem is that, to add this code, we need to slightly alter the format of the CardView XML. The current format starts and concludes the CardView object with one single tag, as follows:

<androidx.cardview.widget.CardView
…
…/>

We need to change the format to a separate opening and closing tag like this (don't change anything just yet):

<androidx.cardview.widget.CardView
…
…
</androidx.cardview.widget.CardView>

This change in format will enable us to add the include… code, and our first CardView object will be complete. With this in mind, edit the code of CardView to be exactly the same as the following code. I have highlighted the two new lines of code, but also note that the forward slash that was after the cardElevation attribute has also been removed:

<androidx.cardview.widget.CardView
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:layout_gravity="center"
   android:layout_margin="@dimen/card_margin"
   app:cardCornerRadius="@dimen/card_corner_radius"
   app:cardElevation="2dp" >

 <include layout="@layout/card_contents_1" />

</androidx.cardview.widget.CardView>

You can now view the main_layout file in the visual designer and see the layout inside the CardView object. The visual designer does not reveal the real aesthetics of CardView. We will see all the CardView widgets scrolling nicely in the completed app shortly. Here is a screenshot of where we are up to so far:

Add two more CardView widgets to the layout and configure them the same as the first, with one exception. On the second CardView object, set cardElevation to 22dp and, on the third CardView object, set cardElevation to 42dp. Also, change the include code to reference card_contents_2 and card_contents_3 respectively.

Tip

You could do this very quickly by copying and pasting the CardView XML and simply amending the elevation and the include code, as mentioned in the previous paragraph.

Now we can run the app and see our three beautiful, elevated CardView widgets in action. In this next screenshot, I have photoshopped two screenshots to be side by side, so you can see one full CardView layout in action (on the left) and, in the image on the right, the effect the elevation setting has, which creates a very pleasing depth with a shadow effect:

Note

The image will likely be slightly unclear in the black and white printed version of this book. Be sure to build and run the app for yourself to see this cool effect.

Now we can play around with editing the theme of the app.