SwiftUI & UI Frameworks







Apple execs say iPadOS 15 helps users to multitask with UI changes


The multitasking changes to iPadOS 15 made it easier for users to understand they could multitask in the first place, a post-WWDC interview with Apple VP of worldwide product marketing Bob Borchers and VP of intelligent system experience Sebastien Marineau-Mes reveals.

Following the keynote of WWDC, executives at Apple surface in extensive interviews to promote the changes launched at the developer conference. In one interview with Borchers and Marineau-Mes focusing on iPadOS 15, the executives cover the multitasking alterations and keyboard shortcuts, as well as other alterations.

Speaking to TechCrunch, Borchers agrees with the sentiment that there was a much-needed change in the way users interacted with multitasking features, referred to as spatial gymnastics.

“The way that we think about this is that the step forward and multitasking makes it easier discover, easier to use even more powerful,” said Borchers. “And, while pros I think were the ones who were using multitasking in the past, we really want to take it more broadly because we think there’s applicability to many, many folks.”

Marineau-Mes jumped in to say one of the goals was to make the spatial model more explicit. “For example, if you’ve got a split view, and you’re replacing one of the windows, we kind of open the curtain and tuck the other app to the side, you can see it — it’s not a hidden mental model, it’s one that’s very explicit,” he said.

As part of the changes this time, affordances to provide users with the knowledge multitasking was an option at all was required. Consistency was a key metric, with the same Slide Over appearance in all views, for example.

“I think we believe strongly in building a mental model where people know where things are [on iPad],” said Marineau-Mes. “And I think you’re right when it comes persistence I think it also applies to, for example, home screen. People have a very strong mental model of where things are in the home screen as well as all of the apps that they’ve configured. And so we try to maintain a well maintained that mental model, and also allow people to reorganize again in the switcher.”

Another goal for iPadOS 15 was to make everything navigable from a keyboard, Marineau-Mes added. “All of the new multitasking affordances and features, you can do through the keyboard shortcuts.”

He continues “You’ve got the new keyboard shortcut menu bar where you can see all the shortcuts that are available. It’s great for discoverability. You can search them and we even, you know, and this is a subtle point, but we even made a very conscious effort to rationalize the shortcuts across Mac and iPadOS.”

Boucher and Marineau-Mes also touched upon the general discoverability of features, Universal Control, and how the Quick Note feature “permeates the system and is easily accessible from everywhere.”

Follow all the details of WWDC 2021 with the comprehensive AppleInsider coverage of the whole week-long event from June 7 through June 11, including details of all the new launches and updates.

Stay on top of all Apple news right from your HomePod. Say, “Hey, Siri, play AppleInsider,” and you’ll get latest AppleInsider Podcast. Or ask your HomePod mini for “AppleInsider Daily” instead and you’ll hear a fast update direct from our news team. And, if you’re interested in Apple-centric home automation, say “Hey, Siri, play HomeKit Insider,” and you’ll be listening to our newest specialized podcast in moments.



How to implement UI state restoration – Discover


People naturally multitask on their devices. Whether they’re switching from app to app, bringing together apps on iPad using Slide Over or Split View, or creating multiple windows of the same app, they should be able to pick up right where they left off — and UI state restoration is a core part of making that experience seamless.

When your app goes out of view, the app’s process is typically put on pause; it’s not given any more CPU time, which keeps the processor free for other tasks. If your app has background processes that are running, the system can even terminate those if an active app needs more resources than currently available.

Restoring the state of your UI is a crucial part of making your app feel responsive — and it’s especially important if you plan to support multiple windows in your iPadOS app. If you have a note-taking app that has four different notes open in different Split View pairings, for example, state restoration helps preserve each note, rather than returning someone to the main screen when they open one of the windows.

Two different types of scenes can be backgrounded and processes halted. These scenes’ states should be saved to restore later.

Meet NSUserActivity

NSUserActivity is a core part of modern state restoration with UIScene and UISceneDelegate: It provides a lightweight way to capture the state of your app and put it to use later, holding key information for both view controllers and important view states — information that can also be used when constructing view controllers for Handoff and Universal Linking.

While what you store in NSUserActivity is up to you, we recommend collecting only the bare minimum so that your app can quickly restore itself. Think of the most unique and simple way you can identify your view controller, like a clear identifier or URL. Include that information, and make sure you can identify where the view controller lives in your navigation and how content should appear within it. For example, when using an Xcode storyboard you may want to store and retrieve view controllers using restoration IDs.

Get started with UI state restoration

The best way to implement UI state restoration is to make your app scene-based, which requires iOS 13, iPadOS 13, Mac Catalyst 10.13, or tvOS 13 or later. (For more information on working with scenes in your app, check out the Developer Library.) Here’s how to get started with scene-based state restoration:

  1. Create a NSUserActivity object to save the app’s state. This can be created in your scene delegate.
  2. In this NSUserActivity, store relevant information (like the current navigation’s state, and view controllers that have been presented or pushed) along with your user’s intent.
  3. Return this NSUserActivity within stateRestorationActivity(for:) in the scene delegate.

You need to collect the right information in each UIScene to pick up where someone left off.

This NSUserActivity will now be stored inside the scene’s stateRestorationActivity property. When your app needs to restore its state, it should do so by looking for this saved NSUserActivity under scene(_:willConnectTo:options:) in the scene delegate.

What about the older view controller-based state restoration APIs?

If you need to support older versions of iOS, macOS, or tvOS, you can use older view controller-based APIs for state restoration via restoration classes and the app delegate. This also means if you want to update your app to adopt UIScene as well as implement UI state restoration across multiple versions of iOS, you will need to implement both scene-based and view-controller based APIs. However, we highly recommend building scene-based UI state restoration.

Compared to the older APIs, modern state restoration requires a different approach to how you define, save, and restore your UI state and your user’s intent. With a scene-based app, you have to separate events in an application’s life cycle and the scene’s life cycle, which means tracking changes also differs. Having multiple scenes means there are many more windows to track, each with unique user actions and navigation history. For some of those windows, you may choose not to restore state depending on their function, requiring state restoration to be more flexible and dependent on how you define the user’s intent.

Prior to the introduction of UIScene, each app had a singular life cycle.

If you can update your app to scene-based restoration and take advantage of NSUserActivity, you’ll also unlock easier pathways to implementing features like Spotlight search, Handoff, enabling Universal Links, and creating new scenes as primary or auxiliary windows. And you’ll provide a smoother and frictionless experience for people using your app, too.


Resources

Watch “Architecting your app for multiple windows”

Watch “Targeting content with multiple windows”

Watch “Window management in your multitasking app”

Learn more about restoring state in non-scene based apps

Explore sample code for restoring your app’s state



An introduction to Jetpack Compose for quick Android UI designs


At Android Dev Summit 2019, Google announced that Jetpack Compose  would be making its way into the Canary release of Android Studio 4.0.

Jetpack Compose could change the way we design Android UIs.

Jetpack Compose is a new tool for designing Android app UIs, which could change the way that we handle layouts across devices. The aim is to speed up development, reduce the amount of code, and ultimately create more elegant and intuitive user interfaces. We’re down for all that!

Also read: Android Studio tutorial for beginners

But is Jetpack Compose really useful? Or is it just another confusing layer on top of countless workflows and methods that are already part of Android development? Let’s dig a little deeper into what it can do, and how to use it.

What is Jetpack Compose?

Jetpack Compose is a declarative reactive UI system. It does away with the need for XML layouts entirely, which is potentially a big get for new developers trying to wrap their heads around new Android projects.

Instead, developers will call Jetpack Compose functions to define elements, and the compiler will do the rest.

What that means, is that you’ll actually be using a series of functions (called composable functions) in order to programmatically describe the UI. To do this, you annotate functions with the @Composable tag. What that tag is actually doing is telling the compiler to create all the boilerplate code for you, which saves time while also keeping our code clean and readable.

The functions won’t be placed anywhere within the flow of your code however (which would have been nice). Instead, you will create a Compose Activity template. Here, you can start adding your elements.

Hello world and beyond with Jetpack Compose

If you want to give Jetpack Compose for Android a go right now, then you can grab it via the Canary build of Android Studio, here. Keep in mind that this is preview software, so it may change with time. Now either start a new Jetpack Compose project, or add Compose support to an existing one.

New Jetpack Compose Project

A cool feature of Compose is the ability to preview your app changes live. That means there’s no need to build your APK and install it on a device/emulator. Just add a second tag @Preview to any functions that take parameters, and you’ll see what you’ve built appear on the right.

When you create your new activity, it will show sample code that displays text to the screen. This looks like so:

setContent {
                Text(“Hello world!”)

}

In this example, the setContent block is setting up the layout of the activity and in there, we have a simple block of text.

The example then goes on to show how you use a composable function with the @Composable annotation. This looks like so:

@Composable
fun Greeting(name: String) {
                Text (text = “Hello $name!”)

}

You can now call this function (only from within the scope of other composable functions) in order to change the name on the label.

Jetpack Compose Example

Getting pretty

This isn’t exactly a UI though – it’s just a piece of text.

If we want to take this further and turn it into something a little more attractive, then we’re going to need some additional functions. Fortunately, there are a good number to pick from.

One example is the Column() function, which will place separate elements in a column layout. As you might  expect, you can also use rows in order to start creating more elaborate layouts of buttons and text.

To add a button, you will do something like this:

Button (
                text = “Button1”,
                onClick = { //place the click listener here }
                style = ContainedButtonStyle()

)

The ContainedButtonStyle() will give you something resembling Material Design.

Graphics are added simply by using DrawImage(). A HeightSpacer will allow you to separate your elements with a little gap. And there are various tools for padding and aligning your various elements.

This is not intended to be a full tutorial by any means. For a more in-depth guide, check out Google’s own documentation. As you can see though, Compose makes it relatively simple to start putting together a basic UI and applying straightforward logic.

Closing thoughts

So that is Compose in a nutshell. What do we make of it?

JetPack Compose is designed to be backwards compatible and to work with your existing apps with minimal changes. That means it will work with existing views, and you can pick and choose elements to use from it.

This is great in theory, but unfortunately there’s still some work to be done if that’s going to be entirely true. For one, compose is Kotlin-only, which will be a pain for those not familiar with it (just one more reason to make the switch, if you haven’t already!). It also means that you won’t always be able to integrate it that quickly into your existing projects.

Learn C# for Android

It’s also worth noting that Compose does not create views, but rather draws directly onto a canvas using drawRec() for things like buttons. So it could get a little bit muddled!

And this is where things could get confusing for newcomers. Imagine that you are trying to learn Android for the first time by reverse engineering an app. Now you not only need to figure out what is Kotlin, XML, and the Android SDK, but you also need to understand where Compose fits into it all. With so many different tools and approaches, Android development can certainly risk becoming overly fragmented and daunting.

But with that said, I certainly see the appeal of being able to quickly whip up a UI to try out a bit of code I’ve written – and Compose definitely makes that a little quicker and easier. Devs who enjoy tinkering might find this an appealing proposition.

Android development risks becoming overly fragmented and daunting.

Let us know in the comments what you make of Jetpack Compose and whether you’d like to see a full tutorial in future. Likewise, be sure to shout out if you want a full tutorial. We’ll be sure to update you once this finds its way to stable.



Building your Android UI: Everything you need to know about Views


Every mobile app has some form of user interface (UI), and in Android user interfaces are created using Views.

If you’re just getting started with Android development, then it makes sense to familiarize yourself with Views as soon as possible, as they’re central to many “Hello World” apps and Android tutorials.

Even if you’ve been developing Android apps for a while, it’s easy to get into a rut! If you’re using the same Views over and over, then now’s the perfect time for a refresher on all the different Views that are included in the Android platform.

In this article, we’ll be taking a closer look at this essential building block of Android development, before exploring some of the most commonly-used Views that you can use in your Android apps.

What is a View, exactly?

View objects, sometimes referred to as “widgets” are the building blocks of all Android UIs.

Each View occupies a rectangular area of the screen and typically draws something that the user can see, such as text or an image. In addition to displaying content, some Views also provide interactive functionality, such as Buttons, EditTexts and Spinners. Whenever an event occurs Android dispatches this event to the appropriate View, which then handles the event and notifies any listeners.

You build your Android UI using a selection of Views

The easiest way to add a View to your Java or Kotlin project, is to define that View within an XML layout resource file. Android provides a simple XML syntax that corresponds to the different View subclasses, for example in the following snippet we’re using XML to instantiate a TextView:

   <TextView
       android:layout_width="wrap_content"
       android:layout_height="wrap_content"
       android:text="Hello World!"
       app:layout_constraintBottom_toBottomOf="parent"
       app:layout_constraintLeft_toLeftOf="parent"
       app:layout_constraintRight_toRightOf="parent"
       app:layout_constraintTop_toTopOf="parent" />

The Android framework is responsible for measuring, laying out and drawing your Views, so you don’t have to explicitly call any methods to perform these actions.

To build a layout, simply keep adding View elements to your XML file, similar to how you create webpages in HTML – just try to keep nesting to a minimum, as it can negatively impact your application’s performance. User interfaces with “shallow” View hierarchies tend to be drawn faster, so if you’re going to deliver a high-performing app then you’ll need to avoid nesting wherever possible.

If you know all of a View’s properties at build time, then you can define this View entirely in XML. By keeping your UI code separate from your application code, you can provide alternate layouts that are optimized for different screen sizes, orientations and languages. This separation also makes your application code easier to read, test and modify, as it isn’t muddled up with UI code.

Since it’s the recommended approach, we’ll be defining Views in XML throughout this tutorial, although you can create Views programmatically where required.

If you need to edit a View’s properties at runtime, then’ll typically have to define some, or all of that View’s properties programmatically in Java or Kotlin. For example, in the following snippet we’re defining a TextView in Java:

//Create a TextView programmatically//

        TextView tv = new TextView(getApplicationContext());

//Define the View’s layout parameters//

        LayoutParams lp = new LinearLayout.LayoutParams(

//Set the View’s width//

                  LayoutParams.WRAP_CONTENT,

//Set the View’s height//

                  LayoutParams.WRAP_CONTENT);

//Apply the layout parameters to the TextView//

        tv.setLayoutParams(lp);

//Set the text//

        tv.setText("Hello World!");

//Add the TextView to the parent ViewGroup//

        rl.addView(tv);
    }
}

Note that you may be able to declare your app’s default layout in XML, and then modify some of its properties at runtime.

Working with Views: Common XML attributes

When creating a View, you’ll need to define various View properties, using XML attributes. Some of these attributes will be unique to that particular View, but there are a number of XML attributes that you’ll encounter over and over again, regardless of the kind of View you’re working with.

Identifying your Views

Every View must have an integer ID that uniquely identifies that particular View. You define integer IDs in your layout files, for example:

android:id="@+id/hello_world"

The + symbol signifies that this is a new name that must be created and added to your project’s R.java file.

When you need to work with a View, you can reference it using its View ID. Typically, you’ll reference a View by creating an instance of that View object in your Activity’s onCreate() method, for example:

TextView myTextView = (TextView) findViewById(R.id.hello_world);

The ID integer technically doesn’t need to be unique throughout the entire tree, just within the part of the tree you’re searching. However, to avoid conflicts and confusion it’s recommended that you use completely unique View IDs, wherever possible.

Layout parameters: Width and height

XML attributes that start with “layout_” define a View’s layout parameters. Android supports a variety of layout parameters, but as a minimum you must define a width and height using the layout_width and layout_height attributes.

Android devices have screens of varying dimensions and pixel densities, so 10 pixels doesn’t translate to the same physical size across every device. If you define a View’s width and height using exact measurements, then this can result in user interfaces that only display and function correctly on devices with specific screens, so you should never use any exact measurements when creating your Views.

Instead, you can define a View’s width and height, using any of the following relative measurements:

  • wrap_content. This View should be just big enough to display its content, plus any padding.
  • match_parent. This View should be as big as its parent ViewGroup will allow.
  • dp. If you need more control over a View’s sizing, then you can provide a density-independent pixel measurement, for example android:layout_width=”50dp.” Note that one dp is roughly equal to one pixel on a “baseline” medium-density screen.
  • sp. If you want to size text using a density-independent pixel measurement, then you should use scalable pixels (sp), for example: android:textSize=”20sp.” Scalable pixels ensure that your app’s text respects the device’s selected text size, so your text will appear bigger on devices that are set to display Large text, and smaller on devices that are set to display Small text.

Give your content some breathing space!

You can use padding to insert some space between the edges of a View and the View’s content, which can be useful for giving your content some “breathing space” and preventing your UI from looking overly busy or cluttered.

The following screenshot shows an ImageView with 10dp of padding:

You can create breathing space by adding padding to your Views

Android provides the following padding attributes:

  • android:padding. Adds extra space to all four edges. If you define a android:padding value, then it’ll take precedence over any edge-specific values, such as paddingLeft and paddingTop, but it won’t override paddingStart or paddingEnd.
  • android:paddingBottom. Adds extra space to the bottom edge.
  • android:paddingEnd. Adds extra space to the end edge.
  • android:paddingHorizontal. Adds extra space to the left and right edges. If you define a android:paddingHorizontal value then it’ll take precedence over paddingLeft and paddingRight, but not paddingStart or paddingEnd.
  • android:paddingLeft. Adds extra space to the left edge.
  • android:paddingRight. Adds extra space to the right edge.
  • android:paddingStart. Adds extra space to the start edge.
  • android:paddingTop. Adds extra space to the top edge.
  • android:paddingVertical. Adds extra space to the top and bottom edges. If you define a android:paddingVertical value, then it’ll take precedence over paddingTop and paddingBottom.

Margins: Adding space around your Views

While padding is applied between the edges of the View and the View’s contents, margins are applied outside of the View’s bounds. You can use margins to create space between your Views, or to create space between a View and the screen’s borders.

If your app contains multiple interactive UI elements, then margins can help ensure the user always activates the correct control, particularly for users who have manual dexterity issues.

Android provides the following margin attributes:

  • android:layout_margin. Adds extra space to the left, top, right and bottom sides of a View, for example android:layout_marginRight=”10dp.” If you define a layout_margin value, then it’ll take precedence over any edge-specific values.
  • android:layout_marginBottom. Adds extra space to the bottom side of the View.
  • android:layout_marginEnd. Adds extra space to the end side of the View.
  • android:layout_marginHorizontal. Adds extra space to the left and right sides of the View. Declaring a layout_marginHorizontal value is equivalent to declaring a layout_marginLeft and a layout_marginRight value. A layout_marginHorizontal value will take precedence over any edge-specific values.
  • android:layout_marginLeft. Adds extra space to the left side of the View.
  • android:layout_marginRight. Adds extra space to the right side of the View.
  • android:layout_marginStart. Adds extra space to the start side of the View.
  • android:layout_marginTop. Adds extra space to the top side of the View.
  • android:layout_marginVertical. Adds extra space to the top and bottom sides of the View. Declaring a layout_marginVertical value is equivalent to declaring a layout_marginTop and a layout_marginBottom value. A layout_marginVertical value will take precedence over any edge-specific values.

What Android Views can I use?

Now we’ve covered some common layout attributes, let’s take a closer look at some of the Views that are provided as part of the Android SDK.

Displaying text, with TextViews

You use TextViews to display text to your users, including interactive text such as hyperlinks, email addresses and phone numbers.

To create a TextView, simply add a <TextView> element to your layout resource file, and then specify your text using the android:text attribute and a string:

 <TextView
        android:id="@+id/hello_world"
        android:layout_height="wrap_content"
        android:layout_width="wrap_content"
        android:text="@string/helloWorld" />

If required, you can set or modify the View’s text at runtime, from your project’s Java code:

public class MainActivity extends Activity {

    protected void onCreate(Bundle savedInstanceState) {
         super.onCreate(savedInstanceState);
         setContentView(R.layout.activity_main);
         final TextView helloWorldTextView = (TextView) findViewById(R.id.hello_world);
         helloWorldTextView.setText(R.string.new_text);
     }
 }

You can also style your text, using elements such as android:textColor, android:fontFamily, and android:textStyle, which has possible values of bold, italic, and bolditalic.

EditTexts: Creating editable, interactive text

EditText is an extension of the TextView class, which allows users to enter text into the View or modify the View’s existing text. Some common examples of EditTexts include login forms where the user can enter their email address and password, and forms where you can enter your payment details.

A login form created using two EditTexts and a ButtonSometimes, an EditText will only accept a certain type of text input, such as a phone number, password, or email address. You can often improve the user experience by declaring the expected input type, which will affect the default keyboard that’s displayed to the user. For example, if your EditText accepts a phone number, then you can use android:inputType=”phone” to display the numerical keyboard and make it easier for the user to enter that telephone number.

<EditText
    android:id="@+id/phoneNumber"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:inputType="phone" />

Android supports a list of inputTypes, including some that specify additional behavior, for example android:inputType=”textPassword” automatically masks the user’s input, which reduces the chances of someone spying on their password.

You’ll find a complete list of supported android:inputType values, over at the official Android docs.

Depending on the expected input type, you may be able to further streamline the user experience by combining inputType values with attributes that define additional behaviour, such as whether to provide spelling suggestions, or automatically capitalize new sentences. For example, if you wanted your EditText to capitalize the first word of a sentence and auto-correct spelling mistakes, then you’d use the following:

android:inputType=
        "textCapSentences|textAutoCorrect

By default, Android’s virtual keyboard provides a user action button, such as a Next or Done button. However, these default actions aren’t always appropriate for the currently-selected EditText, for example if your EditText is a search field, then a Search action makes much more sense than Next or Done.

You can specify an alternative action for your EditText, using the android:imeOptions attribute and one of the many supported values, such as an actionSearch which performs a Search operation using the EditText’s contents.

Finally, sometimes you may want to be notified when the user changes the contents of your EditText. For example if your password EditText requires a password that’s at least ten characters long and features a mixture of letters, symbols and numbers, then you can improve the user experience by automatically checking the user’s input as they’re typing and then notifying them of any issues with their password, before they hit the Register button. You can register to receive these callbacks, by adding a TextWatcher to your EditText.

Displaying PNGs, JPGs and GIFs

You can use the ImageView class to display images. These images can be drawables that you instantiate from an image resource that’s saved in your project, or they can be images that your app downloads over the device’s Internet connection.

To instantiate a drawable from an image resource, you need to add a PNG, JPG or GIF to your project’s res/drawable directory and then reference that file from your XML layout. You’ll need to use the image’s file name as its resource ID, so if you had a file named scenery.jpg then you’d display that image using the following:

<ImageView
         android:id="@+id/myImage"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:src="https://www.androidauthority.com/@drawable/scenery" />

The following screenshot shows this scenery drawable, rendered in Android Studio:

You can display a drawable by adding an ImageView to your layout

Alternatively, in Android 5.0 (API level 21) and higher you can use vector drawables, which define an image as a set of points, lines, and curves. Vector drawables can be scaled without loss of display quality, so you can use a single file for all of Android’s different screen densities.

Creating a custom vector drawable is beyond the scope of this tutorial, but you can get a taste for working with vectors, by taking a look at Vector Asset Studio, which is included as part of Android Studio.

You can use Vector Asset Studio to quickly and easily add any of the stock Material design icons to your project, in vector drawable format:

  • In Android Studio, Control-click your project’s drawable folder.
  • Select New > Vector Asset.
  • In Asset type, select Clip Art.
  • Select the Clip Art button, which displays the Android logo by default.
  • Choose any of the Material design icons; I’m using “done.”

Create a vector asset drawable, using the Vector Asset Studio

  • Give this asset a descriptive name, and then click Next.
  • Read the onscreen information, and if you’re happy to proceed then click Finish.
  • Open your project’s drawable folder and you should see a new XML file that defines your chosen Material icon as a vector drawable. Here’s the contents of my vector drawable resource:
<vector xmlns:android="http://schemas.android.com/apk/res/android"
       android:width="24dp"
       android:height="24dp"
       android:viewportWidth="24.0"
       android:viewportHeight="24.0">
   <path
       android:fillColor="#FF000000"
       android:pathData="M9,16.2L4.8,12l-1.4,1.4L9,19 21,7l-1.4,-1.4L9,16.2z"/>
</vector>

You then just need to reference this vector drawable in your ImageView, in exactly the same way you’d reference a standard drawable resource, for example  android:src=”@drawable/done_vector.”

Buttons and ImageButtons

Buttons and ImageButtons are Views that listen for clicks and then call a method in your code every time the user interacts with that button.

You can communicate the action that’ll occur when the user interacts with your button, using a text label, an icon, or a text label and an icon.

In the following snippet, we’re creating a Button that features a text label:

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"/>

To create an ImageButton, you’ll need to add an image file to your project and then reference it in exactly the same way you referenced your drawables in the previous section. For example:

<ImageButton
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:src="https://www.androidauthority.com/@drawable/button_icon"/>

If you want to create a button that features an image and a text label, then you’ll need to add a text label as normal, and then reference your drawable using one of the following attributes:

  • android:drawableLeft. Position the drawable to the left of the text.
  • android:drawableRight. Position the drawable to the right of the text.
  • android:drawableStart. Position the drawable to the start of the text.
  • android:drawableEnd. Position the drawable to the end of the text.
  • android:drawableTop. Position the drawable above the text.
  • android:drawableBottom. Position the drawable below the text.

Here, we’re creating a button_icon drawable and placing it at the start of the Button’s button_label text:

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"
   android:drawableStart="http://www.androidauthority.com/@drawable/button_icon"/>

In addition to adding labels and images, you can customize your Buttons and ImageButtons by adding a background image or a color resource, using the android:background attribute. For example, you can turn a button blue, by adding the following to your Button or ImageButton declaration:

android:background="#0000FF"

Whenever the user interacts with a button, that Button or ImageButton will receive an onClick event. You’ll need to define a handler for this event, using the android:onClick attribute.

The value of the onClick attribute must correspond to a public method, which will be called in response to the onClick event, for example:

<Button
   android:layout_width="wrap_content"
   android:layout_height="wrap_content"
   android:text="@string/button_label"
   android:onClick="displayToast" />

Next, you’ll need to implement this method in the Activity that’s hosting your Button or ImageButton. This method must be public, return void, and define a View as its only parameter, for example:

 public void displayToast(View view) {
       Toast.makeText(MainActivity.this,
               "Your Message", Toast.LENGTH_LONG).show();

   }

}

Alternatively, you can declare an event handler programmatically. In Java, this means creating an View.OnClickListener object and then assigning it to the Button or ImageButton, using setOnClickListener(View.OnClickListener).

Give your users options, with CheckBoxes

CheckBoxes allow the user to choose one or more options from a vertical list.

CheckBoxes allow you to create vertically-scrolling lists of options.

You create a CheckBox by adding a <Checkbox> item to your XML layout:

    <CheckBox android:id="@+id/yes"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/yes"
        android:onClick="onCheckboxClicked"/>

Since CheckBoxes typically allow the user to select multiple items, you’ll need to add an android:onClick attribute to each individual <CheckBox> element, and then reference the method that’ll be called in response to CheckBox click events.

When you implement the corresponding method in your hosting Activity, you’ll need to verify which CheckBox was selected, and then perform an appropriate action depending on the user’s selection. For example, if we created Yes and No CheckBoxes, then we’d add the following to our hosting Activity:

public void onCheckboxClicked(View view) {
    boolean checked = ((CheckBox) view).isChecked();

//Verify which checkbox is selected//

    switch(view.getId()) {
         case R.id.yes:

//If the “yes” checkbox is selected, then...//

            if (checked)

//Do something//

            else
            Break;

//If the “no” checkbox is selected, then….//

        case R.id.no:

            if (checked)

//Do something//

Views and ViewGroups: Creating RadioButtons

RadioButtons allow the user to choose from a set of mutually-exclusive options, such as the Agree/Disagree buttons commonly found on Terms and Conditions forms.

RadioButtons allow users to choose one or more options from a vertical list

You create each RadioButton by adding a <RadioButton> element to your layout. Since RadioButtons are mutually exclusive you’ll need to arrange all of your <RadioButton> elements inside a <RadioGroup> ViewGroup, which ensures that only one RadioButton can be selected at a time.

<?xml version="1.0" encoding="utf-8"?>
<RadioGroup xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:orientation="vertical">
    <RadioButton android:id="@+id/radio_confirm"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/confirm"
        android:onClick="onRadioButtonClicked"/>
    <RadioButton android:id="@+id/radio_deny"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:text="@string/deny"
        android:onClick="onRadioButtonClicked"/>
</RadioGroup>

You define a click handler by adding the android:onClick attribute to every RadioButton in your RadioGroup, and then implementing the corresponding method in your hosting Activity. Similar to our CheckBox example, this method needs to verify which RadioButton is currently selected, and then take appropriate action based on the user’s selection.

public void onRadioButtonClicked(View view) {
    boolean checked = ((RadioButton) view).isChecked();

//Verify which RadioButton is selected//

    switch(view.getId()) {

//If the “confirm” radio button is selected, then...//

        case R.id.radio_confirm:

            if (checked)

//Do something//

            Break;

//If the “deny” button is selected, then...//

         case R.id.radio_deny:

             if (checked)

//Do something//

Spinner

When tapped, a Spinner displays a set of values as a dropdown menu.

An Android Spinner displays a set of values as a dropdown menu.

The user can tap any item in the Spinner, and your application will perform an action based on their selection. By default, a Spinner always displays the currently-selected value.

A functioning Spinner consists of several components:

  • A <Spinner> element that you add to your layout resource file.
  • A data source that supplies your Spinner with some information; I’ll be using a simple String Array.
  • An ArrayAdapter that converts your data into View items, ready to be displayed in your Spinner.

Let’s start by adding a <Spinner> to our XML layout:

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
   xmlns:android="http://schemas.android.com/apk/res/android"
   xmlns:tools="http://schemas.android.com/tools"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   tools:context=".MainActivity">

   <Spinner
       android:id="@+id/location_spinner"
       android:layout_width="fill_parent"
       android:layout_height="wrap_content" />

</LinearLayout>

If the data is predetermined, then you can provide it as a String Array that’s defined in your Strings.xml file:

<resources>
   <string name="app_name">SimpleSpinner</string>
       <string-array name="location_array">
           <item>Argentina</item>
           <item>Armenia</item>
           <item>Australia</item>
           <item>Belgium</item>
           <item>Brazil</item>
           <item>Canada</item>
           <item>China</item>
           <item>Denmark</item>
           </string-array>
           </resources>

You can then deliver this Array to your Spinner using an instance of ArrayAdapter, which you implement in an Activity or Fragment.

To define an ArrayAdapter, we need to complete the following steps:

  • Create an ArrayAdapter from the String Array, using the createFromResource() method.
  • Specify a layout resource that defines how the user’s chosen item should appear in the Spinner. Android provides a simple_spinner_item layout that you should use unless you specifically require a custom layout.
  • Use setDropDownViewResource(int) to specify which layout the Adapter should use for the Spinner dropdown menu. Once again, Android provides a ready-made layout (simple_spinner_dropdown_item) that should be suitable for most projects.
  • Apply the Adapter to your Spinner, by calling setAdapter().

Here’s my completed code:

Spinner spinner = (Spinner) findViewById(R.id.location_spinner);

//Create an ArrayAdapter//

ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,

//Populate the spinner using the String Array and the simple_spinner_item layout//

        R.array.location_array, android.R.layout.simple_spinner_item);

//Specify the layout that should be used for the dropdown menu//

adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);

//Apply the Adapter to the Spinner//

spinner.setAdapter(adapter);

The Spinner will receive an onItemSelected event every time the user selects an item from the dropdown. To process this event, you’ll need to use the AdapterView.OnItemSelectedListener interface to define an onItemSelected() callback method.

In the following code, I’m displaying a toast every time onItemSelected() is invoked, and incorporating the name of the newly-selected item into my toast. I’m also defining a onNothingSelected() callback method, as this is also required by the AdapterView.OnItemSelectedListener interface.

Here’s the completed Activity:

import androidx.appcompat.app.AppCompatActivity;

import android.os.Bundle;
import android.view.View;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Spinner;
import android.widget.Toast;

public class MainActivity extends AppCompatActivity implements AdapterView.OnItemSelectedListener {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);
       setContentView(R.layout.activity_main);

       Spinner spinner = (Spinner) findViewById(R.id.location_spinner);
       spinner.setOnItemSelectedListener(this);

       ArrayAdapter<CharSequence> adapter = ArrayAdapter.createFromResource(this,

               R.array.location_array, android.R.layout.simple_spinner_item);
                   adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
       spinner.setAdapter(adapter);

   }

   public void onItemSelected(AdapterView<?> parent, View view,
                   int pos, long id) {

       Toast.makeText(parent.getContext(),
               "You've selected n" + parent.getItemAtPosition(pos).toString(),
               Toast.LENGTH_LONG).show();
   }

   @Override
   public void onNothingSelected(AdapterView<?> adapterView) {

//To do//

   }
}

You can download this complete project from GitHub.

ListViews: Displaying your data as scrollable lists

A ListView displays a collection of items as a vertically-scrolling, single column list. When the user selects an item from a ListView, your app will typically perform an action, such as displaying additional information about the selected item.

Android's ListView displays a collection of items as a vertically-scrolling, single column list.

To create a ListView, you’ll need to add a <ListView> element to your XML layout resource file, and then create an Adapter, which will handle the process of displaying each item in your ListView.

Let’s start by adding a <ListView> to our layout:

<?xml version="1.0" encoding="utf-8"?>
    <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent">

    <ListView android:layout_width="fill_parent"
        android:layout_height="fill_parent"
        android:id="@+id/myListView">
    </ListView>

</LinearLayout>

A ListView requests Views on-demand from its assigned Adapter. In our MainActivity, we need to create an Adapter and then associate it with our ListView, using setAdapter(android.widget.ListAdapter).

import android.app.Activity;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.os.Bundle;
import android.widget.ListView;
import android.view.View;
import android.widget.Toast;

public class MainActivity extends Activity {

    String[] countryArray = {"Argentina" , "Armenia", "Australia", "Belgium" ,"Brazil" ,"Canada" , "China" ,
            "Denmark" , "Estonia" , "Finland" , "France" , "Greece" , "Hungary" , "Iceland" , "India" ,
            "Indonesia" , "Italy" , "Japan" , "Kenya" , "Latvia"};

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        final ListView listView = (ListView)findViewById(R.id.myListView);

 ArrayAdapter<String> adapter = new ArrayAdapter<String>(this,android.R.layout.simple_list_item_1, countryArray);
   listView.setAdapter(adapter);

        listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
            @Override
            public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
                Toast.makeText(parent.getContext(),
                        "You've selected n" + parent.getItemAtPosition(position).toString(),
                         Toast.LENGTH_LONG).show();

            }
        }
        )
                ;
    }}

You can download this completed ListView project from GitHub.

Designing unique experiences: Creating custom Views

While there’s no shortage of built-in Views, sometimes you may have very specific requirements that aren’t met by any of Android’s built-in Views. In this scenario you can create your own, custom Android Views.

Most of the time, you’ll create a custom View by identifying a built-in View that almost meets all of your requirements, and then extend this View with your own modifications. However, it’s also possible to create a View from scratch, by extending the base View class.

Creating a custom View is an advanced topic that requires you to complete multiple steps, including providing overrides for the methods that Android usually calls automatically, such as onDraw() and onTouchEvent(), but custom Views can be an effective way to deliver unique experiences to your users.

Wrapping up

In this article, we explored all of the most commonly-used Android Views, plus some of the key attributes you’ll use when creating these Views.

Are there any Views you’d like us to explore in more detail? Let us know in the comments below!