Muy buenas, me llamo Luis y aquà les traigo este nuevo post.
Índice
Introducción
El widget existe desde hace un tiempo en el mundo del escritorio. Fue popularizado por Apple desde el primer lanzamiento de Mac OS X Tiger en 2005.
Los widgets se utilizan principalmente para informar al usuario de la información más reciente de un vistazo. El primer formato del widget para iOS ha sido Today Widget.
Probablemente vea esto cuando deslice el dedo hacia la izquierda de su pantalla de inicio o su Centro de notificaciones.
Pero los widgets no estaban disponibles en la pantalla de inicio hasta que se anunció en la WWDC 2020 para iOS 14, mientras que Android ha tenido Widget en la pantalla de inicio desde el lanzamiento de Android en 2007.
Para esta publicación, crearemos un widget de acertijo simple a partir de un proyecto existente.
- iOS 14
- Xcode 12
¿Cómo funciona el widget?
El widget funciona como una extensión de su aplicación. No puede funcionar como una aplicación independiente. Los widgets están disponibles en tres tamaños (pequeño, mediano, grande) y pueden ser estáticos o configurables.
Un widget es limitado en términos de interacción. No se puede desplazar, solo pulsar. Un widget pequeño solo puede tener un tipo de área de interacción, mientras que los widgets medianos y grandes pueden tener múltiples áreas de interacción que se pueden tocar.
Un widget solo se puede escribir con SwiftUI.
Veamos la arquitectura de una aplicación con WidgetKit. La aplicación es básicamente su proyecto UIKit o SwiftUI. El widget funciona como una extensión fuera de su aplicación. Puede mostrarse en la pantalla de inicio de iOS / iPadOS o en el Centro de notificaciones en macOS.
La lógica compartida podrÃan ser algunos archivos compartidos entre dos membresÃas de destino o su marco compartido.
Recomiendo usar un marco compartido que contenga código reutilizable. También ayuda a su base de código a tener un problema de responsabilidad.
Antes de construir el primer widget, usaremos una aplicación existente que no tiene WidgetKit en el origen. Clone el proyecto de este repositorio git. Entonces abre RiddleProject.xcworkspace.
El proyecto debe contener todo lo que necesitamos para más adelante.
Para crear un nuevo objetivo, presione el botón +
debajo de la membresÃa objetivo.
Luego seleccione Extensión de widget entonces presione próximo.
Entrar a nombre del producto, aquà usaremos RiddleWidget
. Luego desmarque Incluir intención de configuración ya que no queremos hacer un widget configurable y presionar Terminar.
En la siguiente pantalla, tendrá un diálogo para activar el esquema "RiddleWidgetExtension"
? Confirme presionando Activar para que podamos usar para depurar nuestro widget.
Comprender el archivo de plantilla del widget
Abierto RiddleWidget.swift
Timeline Provider es una pieza importante del widget. Proporciona a iOS toda la información de una futura actualización de un widget.
public func placeholder(in context: Self.Context) -> Self.Entry
Este método de marcador de posición se llama cuando se muestra el widget por primera vez que podrÃa estar usando el modificador redacted
.
RecomendarÃa que este método proporcione algunos datos ficticios para poder obtener una vista previa rápidamente.
public func getSnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ())
Este método de instantánea se llama principalmente cuando el widget se encuentra en un estado transitorio, como cuando un usuario está agregando un widget.
Si el widget está en modo de vista previa, recomendarÃa usar algunos datos ficticios para que el usuario pueda obtener una vista previa de cómo se verá si lo agregan a su pantalla de inicio.
WidgetKit proporciona al parámetro un contexto, para que pueda saber si el widget tiene una vista previa de la galerÃa, el tamaño de la familia del widget, el tamaño real del widget.
La finalización le dice al sistema que terminó su tarea asincrónica.
public func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ())
Este método se llama la mayorÃa de las veces cuando el widget se muestra en la pantalla de inicio, necesita devolver una lÃnea de tiempo de entradas.
Es este método el que puede decirle a iOS cuándo es apropiado actualizar un widget. Por ejemplo, una aplicación meteorológica, puede actualizar una vez cada hora, pero para un estado de Stock o Mass Metropolitan, es posible que desee actualizar con más frecuencia.
El objeto de la lÃnea de tiempo que debe devolver al finalizar toma dos parámetros. Las entradas de la lÃnea de tiempo y la polÃtica. La polÃtica sobre cómo la actualización del widget puede ser nunca, después de la última fecha de entrada de la lÃnea de tiempo o después de una hora especÃfica.
SimpleEntry es solo un objeto simple que se ajusta al protocolo de TimelineEntry. La fecha es importante, ya que le dirá a iOS cuando necesite actualizar el widget.
Probablemente agregará como propiedad adicional su modelo para la vista para que pueda vincular fácilmente los datos a su widget.
Simplemente ignore este objeto. El parámetro de marcador de posición en StaticConfiguration
o IntentConfiguration
está en desuso desde Xcode 12 Beta 3. Por lo tanto, es probable que WidgetKit no lo utilice.
EntryView es solo su vista SwitUI de su widget que se muestra en su pantalla de inicio con el uso actual de la entrada de la lÃnea de tiempo como parámetro.
RiddleWidget se ajusta a un Widget de protocolo. Se requerÃa tener un cuerpo de algún tipo de configuración de widget.
Hay dos tipos de configuración de widgets que proporciona el SDK de Apple. Aquà usaremos un Configuración estática ya que no queremos tener un widget configurable.
Si quieres tener un widget configurable por el usuario. Necesitará crear un IntentConfiguration
sino también una intención de Siri. No cubriremos aquà ya que queremos construir un widget simple.
Agregar la biblioteca compartida al widget
La primera parte es agregar una biblioteca compartida a nuestra extensión de widget para que podamos reutilizar nuestro modelo y colores.
En primer lugar, asegúrese de elegir el objetivo correcto seleccionando RiddleWidgetExtension
, luego presione el botón +
debajo de Framework y bibliotecas.
Luego seleccione CommonLibrary
y presione Añadir.
Ahora, deberÃa estar listo para usar el mismo modelo y paletas de colores de la biblioteca común entre la aplicación principal y la extensión del widget.
Creemos este widget. Antes de actualizar nuestro widget, necesitamos importar nuestra biblioteca compartida en la parte superior de struct Provider: TimelineProvider
escribiendo import CommonLibrary
.
struct RiddleWidgetEntryView : View { var entry: Provider.Entry var body: some View { ZStack { Color(.primaryBackground) HStack { Text("🤔") .unredacted() .font(.system(size: 50)) Text("Waiting to get some riddle inserted here from a model") .foregroundColor(Color(.primaryColor)) }.padding() } } }
Entonces ahora, la primera parte será actualizar la propiedad del cuerpo de RiddleWidgetEntryView
. No usaremos el modelo por el momento.
Usaremos un texto estático y deberÃa poder obtener una vista previa. También agregaremos modificador .unredacted()
por lo que no se transformará como vista de marcador de posición durante un estado de carga, por ejemplo.
struct RiddleWidget_Previews: PreviewProvider { static var previews: some View { Group { RiddleWidgetEntryView(entry: SimpleEntry(date: Date())) .previewContext(WidgetPreviewContext(family: .systemMedium)) RiddleWidgetEntryView(entry: SimpleEntry(date: Date())) .redacted(reason: .placeholder) .previewContext(WidgetPreviewContext(family: .systemMedium)) } } }
Actualice RiddleProjectPreview
para que podamos obtener una vista previa del widget en el modo de marcador de posición y en el modo normal.
Por lo tanto, deberÃa poder ver el widget en dos estados. Eso es fantástico, ¿verdad?
struct SimpleEntry: TimelineEntry { public let date: Date public let riddle: Riddle }
Para recuperar el acertijo, necesitamos actualizar el objeto de estructura y agregar una propiedad almacenada adicional para el acertijo.
Xcode debe quejarse de que falta un parámetro de argumento en la instantánea, los métodos de lÃnea de tiempo del proveedor y los métodos de vista previa.
struct Provider: TimelineProvider { public typealias Entry = SimpleEntry public func placeholder(in context: Context) -> SimpleEntry { SimpleEntry(date: Date(), riddle: Riddle.list.first!) } public func getDnapshot(in context: Context, completion: @escaping (SimpleEntry) -> ()) { let entry = SimpleEntry(date: Date(), riddle: Riddle.random()) completion(entry) } public func getTimeline(in context: Context, completion: @escaping (Timeline<Entry>) -> ()) { var entries: [SimpleEntry] = [] // Generate a timeline consisting of five entries an hour apart, starting from the current date. let riddles = Riddle.shuffleList() let currentDate = Date() for hourOffset in 0 ..< 5 { let entryDate = Calendar.current.date(byAdding: .hour, value: hourOffset, to: currentDate)! let entry = SimpleEntry(date: entryDate, riddle: riddles[hourOffset]) entries.append(entry) } let timeline = Timeline(entries: entries, policy: .atEnd) completion(timeline) } }
struct RiddleWidget_Previews: PreviewProvider { static var riddle = Riddle.random() static var previews: some View { Group { RiddleWidgetEntryView(entry: SimpleEntry(date: Date(), riddle: riddle)) .previewContext(WidgetPreviewContext(family: .systemMedium)) RiddleWidgetEntryView(entry: SimpleEntry(date: Date(), riddle: riddle)) .redacted(reason: .placeholder) .previewContext(WidgetPreviewContext(family: .systemMedium)) } } }
Asegurémonos de que RiddleWidgetEntryView
pueda vincular el valor del objeto de entrada que se le pasó.
struct RiddleWidgetEntryView : View { var entry: Provider.Entry var body: some View { ZStack { Color(.primaryBackground) HStack { Text("🤔") .unredacted() .font(.system(size: 50)) Text(entry.riddle.text) .foregroundColor(Color(.primaryColor)) }.padding() } } }
Antes de construir y ejecutar. Asegurémonos de que el widget solo esté disponible para el widget de tamaño mediano agregando un modificador adicional a nuestra configuración estática usando .supportedFamilies([.systemMedium])
.
Y al mismo tiempo, podemos actualizar el Nombre para mostrar del widget y su descripción.
@main struct RiddleWidget: Widget { private let kind: String = "RiddleWidget" public var body: some WidgetConfiguration { StaticConfiguration(kind: kind, provider: Provider()) { entry in RiddleWidgetEntryView(entry: entry) } .supportedFamilies([.systemMedium]) .configurationDisplayName("Riddle of the moment") .description("Display a random riddle each hour.") } }
Ahora, cree y ejecute el widget. DeberÃa ver un buen widget en su pantalla de Inicio.
Pero si toco el widget en este momento, simplemente abre la aplicación pero no muestra el acertijo que se muestra en el widget. Pero, ¿podemos mostrar el contenido relevante?
Eso es lo que aprenderemos a continuación con Universal Links.
Hay dos formas de abrir la aplicación desde un widget. Si su widget es de tamaño mediano o grande, puede usar Link
en una parte de su vista.
Funciona de manera similar a Button
donde la acción está especializada para abrir un enlace web. En nuestro caso, simplificaremos y usaremos el modificador widgetURL(url: URL)
que utilizan toda la parte del widget para abrir la aplicación.
Agreguemos el widgetURL
modificador en RiddleWidgetEntryView
para que la aplicación principal sepa si necesita manejar el enlace universal.
struct RiddleWidgetEntryView : View { var entry: Provider.Entry var body: some View { ZStack { Color(.primaryBackground) HStack { Text("🤔") .unredacted() .font(.system(size: 50)) Text(entry.riddle.text) .foregroundColor(Color(.primaryColor)) }.padding() } .widgetURL(URL(string: "riddle://\(entry.riddle.id)")) } }
Para manejar el enlace universal, su vista necesita registrar un controlador para invocar cuando la vista recibirá una URL. Usaremos el método .onOpenURL(perform: action: @escaping (URL) -> ())
Registremos nuestro controlador como el siguiente código para que podamos extraer la identificación de la URL, encontrar el acertijo relevante que coincida con la identificación y actualizar la vista de contenido.
struct ContentView: View { @State var riddle: CommonLibrary.Riddle @State var isAnswerHidden: Bool = true var body: some View { ZStack { // Some code here } .onOpenURL(perform: { url in let id = url.absoluteString.replacingOccurrences(of: "riddle://", with: "") guard let riddle = Riddle.list.first(where: { $0.id == UInt(id) }) else { return } self.updateRiddle(with: riddle) }) } // Some other code here }
Ahora construyamos y ejecutemos, toque su widget y deberÃa poder ver el acertijo relevante en su aplicación principal.
Aprender y construir un widget es fácil de hacer. WidgetKit es uno de los temas candentes de esta WWDC 20. Al hacer más visible en la pantalla de inicio, el widget será más útil que antes que el antiguo widget Today.
Cuando cree un widget, no traiga demasiada información e interacción. Manténgalo simple para su usuario.
Gracias por leer este post. Feliz codificación.Â
Añadir comentario