Android User Interface
Android device screen is the visual interface for users to view and interact with the application. A well designed UI should be visually appealing, intuitive, consistent and responsive. It should implement esssential accessibility features and adhere to device orientation and cross-device compatibility.
UI consists of various graphical user interface elements built using View and ViewGroup Java/Kotlin objects. These elements include controls like buttons, text boxes, etc. along with images, fonts, colors, themes, and other visual displays. These elements are organized within invisible containers called layouts, which are ViewGroup objects, and determine the positioning of their child Views objects (UI elements) for display on the screen.
The static part of the user interface, excluding any dynamic functionalities, as a convenient option can be designed using XML files or otherwise programmatically using Java or Kotlin. These XML files describe the structure and appearance of the user interface elements. At runtime, the XML files are converted into Java or Kotlin code.
Basic UI Layouts
- Linear Layout - Children views are aligned in a single direction, either horizontally or vertically. It allows for simple linear arrangements of views.
- Relative Layout - Child views are positioned relative to sibling views or the parent container. It provides flexibility in positioning views based on their relationships to each other.
- Table Layout - Child views are arranged in rows and columns, similar to a table. It is useful for creating grid-like structures with consistent cell sizes.
- Frame Layout - Child views are placed at specific locations on the screen or can overlap with each other. It is commonly used for displaying a single view or overlaying views on top of each other.
- Absolute Layout - Child views are positioned at exact locations on the screen, using specific coordinates. It offers precise control over the placement of views but is generally not recommended due to its lack of responsiveness across different screen sizes.
- Constraint Layout - Child views are positioned based on various constraints relative to other views and the parent layout. It provides a more advanced and flexible way of positioning views, taking into account different screen sizes and orientations. Constraint Layout is an improved version of Relative Layout.
- Coordinator Layout - These layouts offer different approaches to organizing and positioning views in an Android app, catering to various design requirements and complexities. Developers can choose the most suitable layout based on their specific needs and desired UI structure.
ViewGroup is the base class for all layouts, which define how all views will be arranged, within its invisible container, such as Linear layout which can contain various views of Buttons, TextViews etc. A ViewGroup can also contain another ViewGroup within it (such as Linear layout within Constraint layout). To display UI of any layout, they are inflated in the corresponding Java/Kotlin class, parsing and converting into a hierarchy of Java (or Kotlin) View objects, forming UI. To inflate layouts Activity class, override onCreate method and use setContentView method, declared within it. For Fragment, override onCreateView and use a layout inflater to get the defined view hierarchy, from XML file.
Using option of Data Binding library simplifies the process of inflating layouts by automatically generating binding classes that provide direct access to views and data within the layout. Enable data binding in the app's build.gradle file. Instead of a regular layout XML file, create a Data Binding layout by enclosing existing layout in a <layout > tag. Data Binding will automatically generate a binding class according to the layout file's name. In activity or fragment, use the generated binding class to inflate the layout without the need of using 'findViewById'. Specific view can be accessed by using binding object (instance of binding class).
Input Controls
- Android Button
- Image Button
- Radio Button
- Switch Button
- Toggle Button
- Edit Text
- Text View
- Check Box
- Rating Bar
- Spinner
- Date Picker
- Time Picker
- Toast Message
- Alert Dialog
- Snackbar
- Sliding Menu with WebView
- Dropdown Menu
- Action Bar/App Bar
- Toolbar
- Action Bar Tabs
- Design Support Library
- Navigation Drawer View
- Floating Action Button (FAB)
- Floating Label for EditText
App Widgets
App widgets are another important UI component. They are self-contained and provide specific functionality, embedded within an application's user interface or placed on the device's home screen. They allow access to certain features or information of app directly without opening the entire application, which is kind of "micro-interaction" with the app's functionality. Android widgets come in different forms and sizes, which include simple controls like buttons and text views to more complex elements like calendars, weather forecasts, music players, news feeds etc. Widgets can be moved around on home screen and can also be resizable, allowing users to adjust their dimensions per their preferences.
To display a widget, touch and hold on empty space on the device screen, tap Widgets and select the app and in its sub-menu specific widget of choice, tap and hold on it and move to the empty space on your home screen.
A example code for a widget at home screen for making a network call is placed at: Widget to fetch JSON data.Custom User Interface
Custom Layout
Creating custom layouts requires a good understanding of Android's view hierarchy, layout calculations, and the specific requirements of UI design. To create custom layouts in Android, extend the ViewGroup class, which allows to modify the appearance and behavior of prebuilt layouts. The following main steps are typically involved:
- Extend the class from the ViewGroup class: Create a new class that extends ViewGroup, serving as the container for custom layout.
- Override the onLayout() method: In this method, define how the custom child views should be positioned within the layout. Specify the coordinates and sizes of each child view based on your desired layout arrangement.
- Override the onMeasure() method: This method is used by the parent to determine the size of the view group. Within this method, calculate the width and height of the view group by measuring the width and height of its child views. Use the getMeasuredWidth() and getMeasuredHeight() methods to obtain the measured dimensions of each child view.
- Override other available methods as needed: Depending on the requirements of custom layout, override additional methods. For example, override methods related to touch events or drawing on the canvas.
Custom Views
Custom views are often created to enhance the appearance and behavior of default views or to create entirely new views. There are several approaches:- Extend the existing Android widget: This involves creating a subclass of an existing Android widget, such as TextView, Button, or ImageView. By extending these widgets, additional functionality or modifications to their behavior are needed. This approach is suitable when it is needed to make specific modifications to an existing view and to ensure reusability by handling necessary setup inside the constructor of your custom view.
- Extend the Android base view: In some cases, it is needed to build a custom view mostly from scratch. In this approach, you extend the base View class or one of its subclasses, such as ViewGroup. This gives complete control over the appearance and behavior of the custom view. Override methods such as onDraw() to handle drawing on the canvas and onTouchEvent() to handle touch events. This approach is suitable for creating highly customized views that do not closely resemble any existing Android widget.
- Grouping existing views together (Compound View): Sometimes, it is needed to create a composite view by grouping multiple existing views together. This is known as a Compound View. In this approach, create a custom view that acts as a container for other views. This allows to encapsulate a set of related views into a single reusable component. You can define the layout and behavior of the compound view by arranging and managing the child views within it.
UI Styles and Themes
Material Design
Material Design provides a consistent and intuitive user interface design across different platforms and devices. Some key aspects include:- Real-world inspiration: Material Design draws inspiration from the physical world, using visual cues that mimic the behavior of objects and materials. It simplifies real-world interactions and animations to create a familiar and intuitive user experience.
- Responsive animations and transitions: Material Design incorporates responsive animations and transitions to provide smooth and meaningful visual feedback to user interactions. These animations help convey the relationships between different UI elements and enhance the overall user experience.
- Grid-based layout: Material Design emphasizes the use of a grid-based layout system. This helps to create a sense of order and consistency in the placement of elements within the interface, ensuring better alignment and organization across different screen sizes and orientations.
- Colors, typography, and depth effects: Material Design introduces a new color palette, typography guidelines, and depth effects such as lighting and shadows. These elements work together to create a visually appealing and cohesive design. The use of depth effects adds a sense of hierarchy and focus to the UI elements.
- New widgets: Material Design introduces new UI widgets that enhance the user interface. For example, the CardView widget allows for the display of important information within cards, maintaining a consistent look and feel. The Toolbar widget replaces the traditional ActionBar and provides more flexibility in customization and placement within the activity. The RecyclerView widget is an updated version of the ListView, offering improved performance, item animations, and more customizable layout options.
- Z-axis dimension: In Material Design, views in Android have a 3D environment. Along with the X and Y dimensions, the Z dimension is also considered. This allows for the creation of layered and depth-aware interfaces, enabling visual elements to appear to be on different planes.
More details about material design in Android and some exmaple are included here: Android Material Design.
Jetpack Compose
Recent arrival of Google's android framework JetPack is a major UI update. It allows building more responsive, modular, declarative and consistent UI designs programmatically using Kotlin, without using XML.
Main Features of Jetpack Compose
- Composable Kotlin functions: UI components are created using composable Kotlin functions with '@Composable' notation. Composable functions define and render UI components and automatically update when the underlying data or state changes. UI hierarchy is built by calling composable functions from other functions.
- Instant code changes view: The @Preview annotation offers preview of composable functions within Android Studio by using stub data to view code changes as they are made in various configurations without running emulator or device. Also, a new tool Live Edit uses real data to allow seeing instant code changes in android device or emulator.
- Interoperability with XML based UI's: Compose offers interoperability with existing Android Views and ViewGroups. Compose components can be embedded within traditional View-based layouts and vice versa. It, thus provides flexibility in adopting Compose incrementally, which can be particularly useful for large and complex projects where a complete migration to Compose based UI may not be feasible in a single step.
- Animations:Compose provides powerful APIs for creating animations and motion effects in the app's UI. Animation APIs allow to define complex animations with ease, including transitions, transformations, and interactions.
- Accessibility support:Compose emphasizes accessibility by providing built-in support for screen readers, keyboard navigation, and other accessibility features. Developers can annotate composable functions with accessibility properties to ensure UI is accessible to all users. Compose provides built-in support for various accessibility features, such as screen readers, keyboard navigation, etc.
- Compose views styling and themes: To decorate or configure a composable, Jetpack Compose uses modifiers. They allow to change the composable's size, layout, appearance or add high-level interactions, such as making an element clickable. Jetpack Compose provides an implementation of Material Design and its UI elements out of the box. Material Design is built around Color, Typography, and Shape. Compose also allows to create various types of lists and supports adding animations.
- Compose State Management: UI updates in a reactive way, in response to state change. Function remember allows to restain state across state recompositions, while rememberSaveable allows using recomposition and configuration changes. The function mutableStateOf creates a mutable state holder that a compose view can observe and change of value triggers recomposition. For more complex state managemnt across configuration changes use ViewModel. Compose handles UI updates and state reactivley but to handle specific stages of activity's lifecycle OnLifecycleEvent in conjunction with LifecycleObserver can be used. Use LaunchedEffect for lifecycle-aware side effects withn composables. Override activity lifecycle methods to manage non-Compose reated tasks and integrate with composables.
- Automation Testing: Tradational automation testing tools like Espresso, JUnit4 / Junit5, Mockito and Robolectric can still be used with Jetpack compose but it also provides its own tools and frameworks for testing, which can complement and sometime replace tradational android testing tools used with non-compose based UI's. UI components in isolation can be tested using ComposeTestRule and Compose testing APIs.
- Some example codes for UI design using JetPack Compose are placed at:
Compose Sample Codes