- Advanced Android with Kotlin
- Android Kotlin Developer
- About this Course
- Join the Path to Greatness
- Advanced Android with Kotlin
- Android Kotlin Developer
- Course Leads
- Murat Yener
- Aleks Haeky
- Sean McQuillan
- Chet Hasse
- Meghan Mehta
- Lyla Fujiwara
- Caren Chang
- What You Will Learn
- Notifications
- Advanced Graphics
- Animation
- Testing
- Login
- Prerequisites and Requirements
- Why Take This Course
- Advanced Android in Kotlin 02.1: Creating Custom Views
- 1. Welcome
- Introduction
- What you should already know
- What you’ll learn
- What you’ll do
- 2. App overview
- 3. Concept: Understanding custom views
- 4. Task. Create a custom view
- Step 1: Create an app with an ImageView placeholder
- Step 2. Create your custom view class
- 5. Concept: Drawing custom views
- 6. Task. Draw the custom view and add it to the layout
- Step 1. Calculate positions and draw the view
- Step 2. Add the view to the layout
- 7. Task. Add view interactivity
- 8. Task: Use custom attributes with your custom view
- 9. Task: Add accessibility
- Step 1. Explore TalkBack
- Step 2. Add content descriptions for dial labels
- Step 3. Add more information for the click action
- 10. Solution code
- 11. Summary
- 12. Learn more
- 13. Homework
- Question 1
- Question 2
- Question 3
- 14. Next codelab
Advanced Android with Kotlin
Develop Feature-Rich Android Apps with the Kotlin Programming Language.
Start Free Course
Related Nanodegree Program
Android Kotlin Developer
Get a Nanodegree certificate that accelerates your career!
About this Course
Go beyond the basics of building an Android app with «Advanced Android with Kotlin». This course teaches you how to add a range of advanced features to your app, starting with best practices for using Android’s notification system. You’ll learn how to create and clip custom views, draw directly to a canvas, and add animations to your apps. You’ll also add maps to your apps and learn to style them. Testing an app is as important as building it, so you’ll learn to test your app to catch and fix bugs so that users never see them. Finally, you’ll learn how to let users login to your app with their existing accounts—you’ll be surprised how little code it takes.
Course Cost
Timeline
Approx. 2 months
Skill Level
intermediate
Included in Product
Rich Learning Content
Interactive Quizzes
Taught by Industry Pros
Self-Paced Learning
Join the Path to Greatness
Master Android development with Kotlin and build professional apps for the world’s most popular mobile platform using Android Studio and Kotlin.
Free Course
Advanced Android with Kotlin
Enhance your skill set and boost your hirability through innovative, independent learning.
Nanodegree Program
Android Kotlin Developer
Built in collaboration with Google, this program will prepare you to become a professional Android developer and allow you to create a diverse portfolio of projects to show employers.
Course Leads
Murat Yener
Aleks Haeky
Sean McQuillan
Chet Hasse
Chief Android Advocate
Meghan Mehta
Lyla Fujiwara
Android Developer Advocate
Caren Chang
What You Will Learn
lesson 1
Notifications
- Send messages to users using notifications
- Design and style notifications
- Add buttons and actions to notifications
- Send push messages using Firebase Cloud Messaging
lesson 2
Advanced Graphics
- Create custom views for your app
- Create and display transformed and clipped regions to the screen
- Build an app that allows users to paint directly on the screen
lesson 3
Animation
- Use animations to draw attention to important UI elements and beautiful designs
- Animate UI elements with property animations
- Use declarative XML with MotionLayout to coordinate animations across multiple views
lesson 4
- Add Google Maps to your Android apps
- Style maps to fit your design
- Enable location services and tracking
lesson 5
Testing
- Learn how to test your app before distribution to avoid crashes or unpredicatable behavior
- Write and run tests for Android, including AndroidX Test
- Test your whole app: UI, data, and code using coroutines, Room, Espresso, and data binding
lesson 6
Login
- Implement user login and identity management for your app using the open source library FirebaseUI
- Enable login and logout for your app’s users
- Control navigation in your app based on whether a user is logged in
Prerequisites and Requirements
General Experience: Comfortable with Object Oriented Programming and Android fundamentals with Kotlin.
See the Technology Requirements for using Udacity.
Why Take This Course
Kotlin is an official language for Android development, and can be used in a variety of other applications, from back-end development to data analysis. It is an open-source, modern programming language that lets developers use both object-oriented and functional programming techniques. It is concise, safe, and fully interoperable with Java. The community of Kotlin developers is growing rapidly, with major companies like Netflix, Pinterest, and Google using Kotlin.
This free course was developed by Kotlin experts at Google, and will teach you how to add a range of advanced features to your app, covering topics such as notifications, maps, testing, identity management, and more.
Источник
Advanced Android in Kotlin 02.1: Creating Custom Views
1. Welcome
This codelab is part of the Advanced Android in Kotlin course. You’ll get the most value out of this course if you work through the codelabs in sequence, but it is not mandatory. All the course codelabs are listed on the Advanced Android in Kotlin codelabs landing page.
This codelab is part of a series that guides you through building custom views, drawing on a canvas, clipping canvas objects, and using shaders for cool effects. We recommend that you do all the codelabs in order, because they progress through tasks step-by-step.
The codelabs in this series are:
Introduction
Android offers a large set of View subclasses, such as Button , TextView , EditText , ImageView , CheckBox , or RadioButton . You can use these subclasses to construct a UI that enables user interaction and displays information in your app. If none of the View subclasses meet your needs, you can create a View subclass known as a custom view.
To create a custom view you can either extend an existing View subclass (such as a Button or EditText ), or create your own subclass of View . By extending View directly, you can create an interactive UI element of any size and shape by overriding the onDraw() method for the View to draw it.
After you create a custom view, you can add it to your activity layouts in the same way you would add a TextView or Button .
This lesson shows you how to create a custom view from scratch by extending View .
What you should already know
- How to create an app with an Activity and run it using Android Studio.
What you’ll learn
- How to extend View to create a custom view.
- How to draw a custom view that is circular in shape.
- How to use listeners to handle user interaction with the custom view.
- How to use a custom view in a layout.
What you’ll do
- Extend View to create a custom view.
- Initialize the custom view with drawing and painting values.
- Override onDraw() to draw the view.
- Use listeners to provide the custom view’s behavior.
- Add the custom view to a layout.
2. App overview
The CustomFanController app demonstrates how to create a custom view subclass by extending the View class. The new subclass is called DialView .
The app displays a circular UI element that resembles a physical fan control, with settings for off (0), low (1), medium (2), and high (3). When the user taps on the view, the selection indicator moves to the next position: 0-1-2-3, and back to 0. Also, if the selection is 1 or higher, the background color of the circular part of the view changes from gray to green (indicating that the fan power is on).
3. Concept: Understanding custom views
Views are the basic building blocks of an app’s UI. The View class provides many subclasses, referred to as UI widgets, that cover many of the needs of a typical Android app’s user interface.
UI building blocks such as Button and TextView are subclasses that extend the View class. To save time and development effort, you can extend one of these View subclasses. The custom view inherits the look and behavior of its parent, and you can override the behavior or aspect of the appearance that you want to change. For example, if you extend EditText to create a custom view, the view acts just like an EditText view, but could also be customized to show, for example, an X button that clears text from the text entry field.
You can extend any View subclass, such as EditText , to get a custom view—pick the one closest to what you want to accomplish. You can then use the custom view like any other View subclass in one or more layouts as an XML element with attributes.
To create your own custom view from scratch, extend the View class itself. Your code overrides View methods to define the view’s appearance and functionality. Key to creating your own custom view is that you are responsible for drawing the entire UI element of any size and shape to the screen. If you subclass an existing view such as Button , that class handles drawing for you. (You’ll learn more about drawing later in this codelab.)
To create a custom view follow these general steps:
- Create a custom view class that extends View , or extends a View subclass (such as Button or EditText ).
- If you extend an existing View subclass, override only the behavior or aspects of the appearance that you want to change.
- If you extend the View class, draw the custom view’s shape and control its appearance by overriding View methods such as onDraw() and onMeasure() in the new class.
- Add code to respond to user interaction and, if necessary, redraw the custom view.
- Use the custom view class as a UI widget in your activity’s XML layout. You can also define custom attributes for the view, to provide customization for the view in different layouts.
4. Task. Create a custom view
In this task you will:
- Create an app with an ImageView as a temporary placeholder for the custom view.
- Extend View to create the custom view.
- Initialize the custom view with drawing and painting values.
Step 1: Create an app with an ImageView placeholder
- Create a Kotlin app with the title CustomFanController using the Empty Activity template. Make sure the package name is com.example.android.customfancontroller .
- Open activity_main.xml in the Text tab to edit the XML code.
- Replace the existing TextView with this code. This text acts as a label in the activity for the custom view.
- Add this ImageView element to the layout. This is a placeholder for the custom view you will create in this codelab.
- Extract string and dimension resources in both UI elements.
- Click the Design tab. The layout should look like this:
Step 2. Create your custom view class
- Create a new Kotlin class called DialView .
- Modify the class definition to extend View . Import android.view.View when prompted.
- Click on View and then click the red bulb. Choose Add Android View constructors using ‘@JvmOverloads’. Android Studio adds the constructor from the View class. The @JvmOverloads annotation instructs the Kotlin compiler to generate overloads for this function that substitute default parameter values.
- Above the DialView class definition, just below the imports, add a top-level enum to represent the available fan speeds. Note that this enum is of type Int because the values are string resources rather than actual strings. Android Studio will show errors for the missing string resources in each of these values; you’ll fix that in a later step.
- Below the enum , add these constants. You’ll use these as part of drawing the dial indicators and labels.
- Inside the DialView class, define several variables you need in order to draw the custom view. Import android.graphics.PointF if requested.
- The ** radius ** **is the current radius of the circle.** This value is set when the view is drawn on the screen.
- The ** fanSpeed ** **is the current speed of the fan**, which is one of the values in the FanSpeed enumeration. By default that value is OFF .
- Finally ** postPosition ** **is an X,Y** point that will be used for drawing several of the view’s elements on the screen.
These values are created and initialized here instead of when the view is actually drawn, to ensure that the actual drawing step runs as fast as possible.
- Also inside the DialView class definition, initialize a Paint object with a handful of basic styles. Import android.graphics.Paint and android.graphics.Typeface when requested. As previously with the variables, these styles are initialized here to help speed up the drawing step.
- Open res/values/strings.xml and add the string resources for the fan speeds:
5. Concept: Drawing custom views
Once you have created a custom view, you need to be able to draw it. When you extend a View subclass such as EditText , that subclass defines the view’s appearance and attributes and draws itself on the screen. Consequently, you don’t have to write code to draw the view. You can override methods of the parent to customize your view instead.
If you are creating your own view from scratch (by extending View ), you are responsible for drawing the entire view each time the screen refreshes, and for overriding the View methods that handle drawing. In order to properly draw a custom view that extends View , you need to:
- Calculate the view’s size when it first appears, and each time that view’s size changes, by overriding the onSizeChanged() method.
- Override the onDraw() method to draw the custom view, using a Canvas object styled by a Paint object.
- Call the invalidate() method when responding to a user click that changes how the view is drawn to invalidate the entire view, thereby forcing a call to onDraw() to redraw the view.
The onDraw() method is called every time the screen refreshes, which can be many times a second. For performance reasons and to avoid visual glitches, you should do as little work as possible in onDraw() . In particular, don’t place allocations in onDraw() , because allocations may lead to a garbage collection that may cause a visual stutter.
The Canvas and Paint classes offer a number of useful drawing shortcuts:
- Draw text using drawText() . Specify the typeface by calling setTypeface() , and the text color by calling setColor() .
- Draw primitive shapes using drawRect() , drawOval() , and drawArc() . Change whether the shapes are filled, outlined, or both by calling setStyle() .
- Draw bitmaps using drawBitmap() .
Note: In apps that have a deep view hierarchy, you can also override the onMeasure() method to accurately define how your custom view fits into the layout. That way, the parent layout can properly align the custom view. The onMeasure() method provides a set of measureSpecs that you can use to determine your view’s height and width. To learn more about overriding onMeasure() , see Custom Components.
You’ll learn more about Canvas and Paint in a later codelab. To learn more about how Android draws views, see How Android Draws Views.
6. Task. Draw the custom view and add it to the layout
In this task you will draw the fan controller custom view onto the screen—the dial itself, the current position indicator, and the indicator labels—with the onSizeChanged() and onDraw() methods. You’ll also create a helper method, computeXYForSpeed(), to calculate the current X,Y position of the indicator label on the dial.
Step 1. Calculate positions and draw the view
- In the DialView class, below the initializations, override the onSizeChanged() method from the View class to calculate the size for the custom view’s dial. Import kotlin . math.min when requested.
The onSizeChanged() method is called any time the view’s size changes, including the first time it is drawn when the layout is inflated. Override onSizeChanged() to calculate positions, dimensions, and any other values related to your custom view’s size, instead of recalculating them every time you draw. In this case you use onSizeChanged() to calculate the current radius of the dial’s circle element.
- Below onSizeChanged() , add this code to define a computeXYForSpeed() extension function for the PointF class. Import kotlin.math.cos and kotlin.math.sin when requested. This extension function on the PointF class calculates the X, Y coordinates on the screen for the text label and current indicator (0, 1, 2, or 3), given the current FanSpeed position and radius of the dial. You’ll use this in onDraw().
- Override the onDraw() method to render the view on the screen with the Canvas and Paint classes. Import android.graphics.Canvas when requested. This is the skeleton override:
- Inside onDraw() , add this line to set the paint color to gray ( Color.GRAY ) or green ( Color.GREEN ) depending on whether the fan speed is OFF or any other value. Import android.graphics.Color when requested.
- Add this code to draw a circle for the dial, with the drawCircle() method. This method uses the current view width and height to find the center of the circle, the radius of the circle, and the current paint color. The width and height properties are members of the View superclass and indicate the current dimensions of the view.
- Add this following code to draw a smaller circle for the fan speed indicator mark, also with the drawCircle() method This part uses the PointF . computeXYforSpeed() extension method to calculate the X,Y coordinates for the indicator center based on the current fan speed.
- Finally, draw the fan speed labels (0, 1, 2, 3) at the appropriate positions around the dial. This part of the method calls PointF.computeXYForSpeed() again to get the position for each label, and reuses the pointPosition object each time to avoid allocations. Use drawText() to draw the labels.
The completed onDraw() method looks like this:
Step 2. Add the view to the layout
To add a custom view to an app’s UI, you specify it as an element in the activity’s XML layout. Control its appearance and behavior with XML element attributes, as you would for any other UI element.
- In activity_main.xml , change the ImageView tag for the dialView to com.example.android.customfancontroller.DialView , and delete the android:background attribute. Both DialView and the original ImageView inherit the standard attributes from the View class, so there is no need to change any of the other attributes. The new DialView element looks like this:
- Run the app. Your fan control view appears in the activity.
7. Task. Add view interactivity
The final task is to enable your custom view to perform an action when the user taps the view. Each tap should move the selection indicator to the next position: off-1-2-3 and back to off. Also, if the selection is 1 or higher, change the background from gray to green, indicating that the fan power is on.
To enable your custom view to be clickable, you:
- Set the view’s isClickable property to true . This enables your custom view to respond to clicks.
- Implement the View class’s performClick() to perform operations when the view is clicked.
- Call the invalidate() method. This tells the Android system to call the onDraw() method to redraw the view.
Normally, with a standard Android view, you implement OnClickListener() to perform an action when the user clicks that view. For a custom view, you implement the View class’s performClick() method instead, and call super . performClick(). The default performClick() method also calls onClickListener() , so you can add your actions to performClick() and leave onClickListener() available for further customization by you or other developers that might use your custom view.
- In DialView.kt , inside the FanSpeed enumeration, add an extension function next() that changes the current fan speed to the next speed in the list (from OFF to LOW , MEDIUM , and HIGH , and then back to OFF ). The complete enumeration now looks like this:
- Inside the DialView class, just before the onSizeChanged() method, add an init() block. Setting the view’s isClickable property to true enables that view to accept user input.
- Below init(), override the performClick() method with the code below.
The call to super . performClick() must happen first, which enables accessibility events as well as calls onClickListener() .
The next two lines increment the speed of the fan with the next() method, and set the view’s content description to the string resource representing the current speed (off, 1, 2 or 3).
FInally, the invalidate() method invalidates the entire view, forcing a call to onDraw() to redraw the view. If something in your custom view changes for any reason, including user interaction, and the change needs to be displayed, call invalidate().
- Run the app. Tap the DialView element to move the indicator from off to 1. The dial should turn green. With each tap, the indicator should move to the next position. When the indicator returns to off, the dial should turn gray again.
8. Task: Use custom attributes with your custom view
This example shows the basic mechanics of using custom attributes with your custom view. You define custom attributes for the DialView class with a different color for each fan dial position.
- Create and open res/values/attrs.xml .
- Inside , add a resource element.
- Inside the resource element, add three attr elements, one for each attribute, with a name and format . The format is like a type, and in this case, it’s color .
Note: The attr name is, by convention, the same name as the name of the class that defines the custom view (in this case, DialView ). Although it’s not strictly necessary to follow this convention, many popular code editors depend on this naming convention to provide statement completion.
- Open the activity_main.xml layout file.
- In the DialView , add attributes for fanColor1 , fanColor2 , and fanColor3 , and set their values to the colors shown below. Use app: as the preface for the custom attribute (as in app:fanColor1 ) rather than android: because your custom attributes belong to the schemas.android.com/apk/res/ your_app_package_name namespace rather than the android namespace.
In order to use the attributes in your DialView class, you need to retrieve them. They are stored in an AttributeSet , which is handed to your class upon creation, if it exists. You retrieve the attributes in init , and assign the attribute values to local variables for caching.
- Open the DialView.kt class file.
- Inside the DialView , declare variables to cache the attribute values.
- In the init block, add the following code using the withStyledAttributes extension function. You supply the attributes and view, and set your local variables. Importing withStyledAttributes will also import the right getColor() function.
Android and the Kotlin extension library ( android-ktx ) do a lot of work for you here! The android-ktx library provides Kotlin extensions with a strong quality-of-life focus. For example, the withStyledAttributes extension replaces a significant number of lines of rather tedious boilerplate code. For more on this library, check out the documentation, and the original announcement blog post!
- Use the local variables in onDraw() to set the dial color based on the current fan speed. Replace the line where the paint color is set ( paint . color = if ( fanSpeed == FanSpeed. OFF ) Color. GRAYelse Color. GREEN ) with the code below.
- Run your app, click on the dial, and the color setting should be different for each position, as shown below.