ストリーミングはほとんどのブラウザと
Developerアプリで視聴できます。
-
UIKitボタンシステムについて
すべてのAppでボタンが使用されています。iOS 15では、更新されたスタイルを採用して、インターフェイスに簡単にフィットする見映えの良いボタンを作成できます。さまざまなタイプのボタンを簡単に作成可能にする各種の機能を確認して、よりリッチなインタラクションを実現する方法について解説し、Mac Catalystの使用時に優れたボタンを提供する方法を紹介します。
リソース
関連ビデオ
WWDC21
-
ダウンロード
♪ ♪ Hi. I’m David Duncan, and with my colleague, Eric Dudiak, we’re going to be discussing all the ways that UIKit makes buttons better in iOS 15.
The humble button, a staple of apps large and small. Buttons are perhaps the most common way to solicit user input. Buttons come in many forms: large and small; with images, text, or both; with and without backgrounds; and every color of the rainbow. Let’s start by focusing on a few specific styles.
In iOS 15, UIKit now provides these four basic styles. Adding to the plain style you already know and love are the new gray, tinted, and filled styles.
But UIKit doesn’t just make buttons more stylish in iOS 15. It also makes them more powerful. Dynamic type is now supported by default, and multiline text support is built into button system.
Accessibility has been enhanced with better support for all accessibility features as well as generating buttons that are more accessible by default. And with all these new features, buttons are more customizable than ever, so you can get exactly the style you want. So with that primer, let’s meet UIButtonConfiguration, the entry point to the new button system.
Welcome to Button Emporium, the premier supplier of buttons of all shapes and sizes.
Button Emporium always wants to have the best buttons, so let’s update the app to adopt UIButtonConfiguration... starting with the all-important Sign In button.
Currently the app generates a Sign In button with this code, generating a plain system button with the title “Sign In”.
But this is a super important button, so let’s make it stand out more using the new filled style.
And we’re done! It’s easy to get started with UIButtonConfiguration, as UIButton automatically integrates titles and images set with the existing API on configurations you provide, making it easy to update your button’s style without updating all your code at once. But when you’re ready to update your code, there is plenty more to UIButtonConfiguration than just styles. Let’s take a look at that next.
This is our current “Add to Cart” button.
It’s a pretty basic button right now, but we’re going to take advantage of new features offered by UIButtonConfiguration to turbo charge the button-buying experience.
To start, we’ll use the tinted style as it complements our other buttons. We start by creating a tinted button configuration, set its title, matching how we previously configured our button.
Next we create the button with our filled out configuration.
This is already quite an improvement, but let’s take it over the top. The next improvement we’ll make is to add an image to the button, making it simple to determine what it does at a glance.
Our designer really wants the image in the trailing position, so alongside setting the image property, we also set the imagePlacement property, putting the image exactly where we want it.
But there are two more features we want to add to our new “Add to Cart” button.
The first is to preview what happens when you order multiple items, which will use the subtitle feature of UIButtonConfiguration.
The second is to switch from the outlined image to its filled version when the button is pressed.
For that, we need to update the image property at the appropriate time.
In order to update the button correctly when either of these changes occur, we’ll add a configurationUpdateHandler.
The configurationUpdateHandler is called when the button needs an update, allowing you to make centralized changes.
Usually you’ll change the button’s configuration, so it typically begins by obtaining a starting configuration and ends with setting the changed configuration.
Here we start with the button’s existing configuration, but you can just as easily create a new one and fill out all of its parameters instead.
First let’s set the correct image for the button. When the button is pressed, isHighlighted returns true, and we set the filled version of our cart symbol.
Otherwise, we use the outlined version.
Since isHighlighted is a state of UIButton, it automatically arranges for the configurationUpdateHandler to be called when that value changes.
Next, we update the subtitle when itemQuantityDescription changes. But itemQuantityDescription isn’t a property of UIButton. How do we arrange for the configurationUpdateHandler to be called when the value changes? When the customer changes the number of buttons to be purchased, the app updates itemQuantityDescription.
To ensure that the Add to Cart button also updates, our didSet handler calls setNeedsUpdateConfiguration, which in turn arranges for the configurationUpdateHandler to be called and triggers an update of the button.
At Button Emporium, we’ve never met a button we didn’t like, and with UIButtonConfiguration, there is plenty to like.
Before we update our next button, let’s quickly cover some other features.
Buttons can now show an activity indicator, making it easy to provide feedback that your app is busy.
Just set showsActivityIndicator to true in your button configuration, and we’ll show the indicator, replacing the image if necessary.
Adjusting aspects of the button’s layout is straightforward, giving you more control over how content is positioned in the button. Here you can see how contentInsets reserve space on the edges of the button, and imagePadding and titlePadding allow us to increase the space between those elements.
And while UIKit will layout these components automatically, you have control over how titles align with each other as well as how the button’s content aligns inside the content region.
Semantic stylings make it simple to create buttons with cohesive styles without having to dig into details.
Starting with a simple filled button, we configure the baseBackgroundColor, baseForegroundColor, cornerStyle, and buttonSize to generate a customized button, and you automatically get thematic states, such as pressed and disabled without any extra effort.
But even with lots of automation, it’s still easy to make detailed customizations for those times when you simply must have exactly what you need, like with our all-important “Check Out” button.
To ensure that Button Emporium customers can get their buttons with a minimum of fuss, the check out button is big and easy to find.
To build it, we’ll start with the filled style, set its size to large, and fill out its image and title.
When the button is tapped, we start processing the cart and want to show an activity indicator.
To enable this, we add a configurationUpdateHandler to manage the showsActivityIndicator property of the configuration.
Just as before, changes to the isCartBusy property will call setNeedsUpdateConfiguration on the check out button to ensure the activity indicator is turned on and off as necessary.
And while blue is nice, we want to make sure to leave an impression.
So to ensure our precise color is used for the background, let’s set the backgroundColor of UIButtonConfiguration’s UIBackgroundConfiguration. That’s way better.
Now that we’ve discussed how UIButtonConfiguration can make your buttons look better than ever, I’ll hand it over to Eric to talk about other new things that buttons can do. Thanks, David. Now that we’ve checked out how buttons can have their appearance customized, let’s inspect how buttons can have their functionality customized. Most buttons are just simple push buttons, but sometimes a button needs a bit of extra behavior. The first ones we’re going to examine is the toggle button.
These buttons preserve the selected state from UIControl. They automatically toggle it on and off each time the button is pressed.
It also can be programmatically changed as necessary.
In addition to built-in styles for the on and off states, we can take advantage of the UIButtonConfiguration to customize the presentation of these on and off states.
The concept of toggle buttons on iOS is not new. You may have noticed some buttons like the lyrics button in the Music app.
It toggles the lyrics on and off in the player like this.
Functionally, this works just like UISwitch, but it saves some space in the UI and it fits the design of the app much better.
Toggle buttons also work off UIBarButtonItems like this one in Calendar.
In the top bar, the day details can be enabled and disabled.
Pushing it toggles the display of the details.
In this case, there is a new selected property on UIBarButtonItem that can be read or set for the selected state. Now let’s update Button Emporium to adopt toggle buttons.
Our app lets us browse for the kinds of buttons we want to buy. But while browsing, I only want to peruse what’s currently in stock. Here, we’ve added a toggle button to toggle between showing absolutely everything and just what’s in stock and ready to ship. This is a great use of the toggle button. One advantage is that, since it’s a button, the label is part of it, making it very clear what is being toggled here.
So let’s check out how we made that. Here, we have the basics of setting up a button. To make it a toggle button, we just set changesSelectionAsPrimaryAction to true. Now it’s a toggle button. That’s it.
We can also set the selected state to match our internal model.
Now, we might want something a little more complicated that just two states of on and off. For buttons that can have more options to switch between, we can use pop-up buttons. Pop-up buttons are a close relative to pull-down buttons, which already exist in iOS. These present a menu when pressed. Pop-up buttons take that a step further and ensure that one and only one of the menu elements is ever selected.
They also show that current selection as their title and image. Building a pop-up button is actually an extension of building a pull-down button. For those, a menu is assigned to the button. To make the menu the default action, the showsMenuAsPrimaryAction property is set to true.
Pop-up buttons take that one step further by just turning on the changesSelectionAsPrimaryAction property. That’s all it takes. They work like UISegmentedControl but can be useful when there are more choices than might fit on the segmented control. They can also be useful for cases where the choices have an inherent hierarchy.
Some examples of this style of button exist today. For example, the Phone app uses a pop-up button to switch between SIMs for outgoing calls.
And here the button presents a menu. Selecting secondary switches the line. As a result, the button is updated to the new outgoing line. The label and image have been updated to display the new selection.
Similarly, we have some use for this in Button Emporium. When we’re browsing buttons, we have some that come in a variety of colors. The number of colors is a fixed set to choose from, but probably too big for a segmented control, but it’s also small enough that we really want to change it in-line.
This is a great use of a pop-up button because we want the selection to be the title of the button. We can then present all the color choices.
And on a new selection, our app can just update for the color choice.
Let’s investigate the code for that. Here we actually have the code to make a simple pull-down menu that we can just update.
Just like the toggle button, we switch changesSelectionAsPrimaryAction to true. And now it’s a pop-up button.
If we want to have a particular color be the default selection instead of just the first color in the list, we can preassign that one to “on” when we set the menu.
That will make it the default selection.
We can check the selection by asking the button’s menu for the current selectedElements, which will always have exactly a single element.
And if we need to set a new one in code, we can just change the state on the element from the button’s menu property.
Pop-up buttons can also be created in Interface Builder, but in this case we’re going to want to retrieve the colors dynamically from the server instead of using a fixed list, so we’re gonna do it in code. To learn more about using the new button system and button types with Interface Builder, check out the “Build interfaces with style” video.
One of the best parts of these new button types is that they automatically work on Mac Catalyst. Mac users expect buttons to look and behave a certain way, including pull-downs, pop-ups, and toggle buttons. With these iOS buttons, they automatically get updated to their Mac versions.
So here we have a selection of buttons from an iPad app, like we’ve been using throughout the presentation, which include the default borderless buttons and some using the new configurations as well as pop-up and pull-down buttons.
And here they are with no manual changes on Mac Catalyst. Just the way a seasoned Mac user would expect. We get the standard bezeled buttons, including the Mac indicators for pull-down and pop-up buttons.
In some cases, however, the extra customization of the iPad buttons may be more appropriate even for a Mac app. For that, button support changing the behavior style from the default of automatic to iPad.
This is useful for very prominent, custom buttons in an app, like the check out button we made earlier. For more information about building and customizing Mac Catalyst apps, check out the “What’s new in Mac Catalyst” video.
As you may have noticed in the pop-up button examples, much of the functionality is built on top of new and existing features of UIMenu.
UIMenu pairs really well with UIButton and UIBarButtonItem for lots of great interactions. We’ve explored how you can adjust the behavior of buttons to create both pop-up buttons and pull-down buttons. On iOS and iPadOS, these behaviors are independent of the visual customizations, so you can easily combine them with UIButtonConfiguration to create lots of different button styles.
These buttons also benefit from improvements in menus like the ability for menu items to have subtitles for greater clarity.
On top of that, submenu navigation on iOS and iPadOS has also been improved, allowing the creation of hierarchies within a menu. And in some cases, you might want the submenu of a pull-down button to behave as a single-selection menu itself. This can be useful if you have a “sort-by” menu within an action menu, for example. Some of the new menu improvements make this much easier to create.
Here’s a custom pull-down bar button item using a submenu in our code.
It has a couple of actions and then a submenu for sorting results. Instead of manually turning on and off the menu items within that submenu, we’re just gonna indicate that this submenu is for single selection when we create it. Now it gets the same automatic selection behavior that pop-up buttons get but just within the submenu. Only one selected element will be allowed, and the element selected will be updated when the user taps it.
It can be updated or accessed in code in the exact same way as we did earlier with the pop-up menu.
And single-selection behavior works if the menu has its own submenu. Only one element in the entire subtree then can be selected at a time. And the selectedElements property includes selection in submenus, making the access just as easy as if we didn’t have a submenu.
So that’s how to make better buttons in your app. Add configurations to buttons to get more control over the styling to unlock much richer styling while still staying consistent with the platform.
Also explore ways to replace existing picker interfaces or controls with pop-up or toggle buttons to get more streamlined interactions.
With these changes, you will likely find UIButton subclasses that can be removed or simplified.
And because the system can better understand your buttons, you’ll get much better Mac Catalyst conversion automatically. Thank you for joining us, and I hope you’ve enjoyed this deep dive into the world of buttons. [upbeat music]
-
-
2:13 - Creating a button with a configuration
// Create the Sign In button let signInButton = UIButton(type: .system) signInButton.configuration = .filled() signInButton.setTitle("Sign In", for: [])
-
3:20 - Customizing a button configuration
// Create the Add to Cart button var config = UIButton.Configuration.tinted() config.title = "Add to Cart" config.image = UIImage(systemName: "cart.badge.plus") config.imagePlacement = .trailing addToCartButton = UIButton(configuration: config, primaryAction: …)
-
4:45 - Customizing a button with a configuration update handler
// Customize image and subtitle with a configurationUpdateHandler addToCartButton.configurationUpdateHandler = { [unowned self] button in var config = button.configuration config?.image = button.isHighlighted ? UIImage(systemName: "cart.fill.badge.plus") : UIImage(systemName: "cart.badge.plus") config?.subtitle = self.itemQuantityDescription button.configuration = config }
-
5:59 - Indicating a configuration needs an update
// Update addToCartButton when itemQuantityDescription changes private var itemQuantityDescription: String? { didSet { addToCartButton.setNeedsUpdateConfiguration() } }
-
8:26 - A completely customized button
// Configure the button background var config = UIButton.Configuration.filled() config.buttonSize = .large config.image = UIImage(systemName: "cart.fill") config.title = "Checkout" config.background.backgroundColor = .buttonEmporium let checkoutButton = UIButton(configuration: config primaryAction: …) addToCartButton.configurationUpdateHandler = { [unowned self] button in var config = button.configuration config?.showsActivityIndicator = self.isCartBusy button.configuration = config }
-
11:56 - Creating a toggle button
// Toggle button // UIAction setup let stockToggleAction = UIAction(title: "In Stock Only") { _ in toggleStock() } // The button let button = UIButton(primaryAction: stockToggleAction) button.changesSelectionAsPrimaryAction = true // Initial state button.isSelected = showingOnlyInStock()
-
14:30 - Creating a pop-up button
// Pop-up button let colorClosure = { (action: UIAction) in updateColor(action.title) } let button = UIButton(primaryAction: nil) button.menu = UIMenu(children: [ UIAction(title: "Bondi Blue", handler: colorClosure), UIAction(title: "Flower Power", state: .on, handler: colorClosure) ]) button.showsMenuAsPrimaryAction = true button.changesSelectionAsPrimaryAction = true // Update to the currently set one updateColor(button.menu?.selectedElements.first?.title) // Update the selection (button.menu?.children[selectedColorIndex()] as? UIAction)?.state = .on
-
18:18 - Creating a custom single selection menu
// Single selection menu // The sort menu let sortMenu = UIMenu(title: "Sort By", options: .singleSelection, children: [ UIAction(title: "Title", handler: sortClosure), UIAction(title: "Date", handler: sortClosure), UIAction(title: "Size", handler: sortClosure) ]) // The top menu let topMenu = UIMenu(children: [ UIAction(title: "Refresh", handler: refreshClosure), UIAction(title: "Account", handler: accountClosure), sortMenu ]) let sortSelectionButton = UIBarButtonItem(primaryAction: nil, menu: topMenu) updateSorting(sortSelectionButton.menu?.selectedElements.first)
-
-
特定のトピックをお探しの場合は、上にトピックを入力すると、関連するトピックにすばやく移動できます。
クエリの送信中にエラーが発生しました。インターネット接続を確認して、もう一度お試しください。