Skip to content

//workflow/com.squareup.workflow1.ui/DecorativeViewFactory

DecorativeViewFactory

[androidJvm] @WorkflowUiExperimentalApi()

class DecorativeViewFactory<OuterT : Any, InnerT : Any>(type: KClass<OuterT>, map: (OuterT, ViewEnvironment) -> Pair<InnerT, ViewEnvironment>, viewStarter: ViewStarter?, doShowRendering: (view: View, ViewShowRendering<InnerT>, OuterT, env: ViewEnvironment) -> Unit) : ViewFactory<OuterT>

This will be deprecated in favor of ScreenViewFactory.toUnwrappingViewFactory very soon.

A ViewFactory for OuterT that delegates view construction responsibilities to the factory registered for InnerT. Makes it convenient for OuterT to wrap instances of InnerT to add information or behavior, without requiring wasteful wrapping in the view system.

One general note: when creating a wrapper rendering, you’re very likely to want it to implement Compatible, to ensure that checks made to update or replace a view are based on the wrapped item. Each example below illustrates this.

Examples

To make one rendering type an “alias” for another – that is, to use the same ViewFactory to display it – provide nothing but a single-arg mapping function:

1
2
3
4
5
6
7
class OriginalRendering(val data: String) : AndroidViewRendering<OriginalRendering> {...}
class AliasRendering(val similarData: String)

object DecorativeViewFactory : ViewFactory<AliasRendering>
by DecorativeViewFactory(
  type = AliasRendering::class, map = { alias -> OriginalRendering(alias.similarData) }
)

To make a decorator type that adds information to the ViewEnvironment:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
class NeutronFlowPolarity(val reversed: Boolean) {
  companion object : ViewEnvironmentKey<NeutronFlowPolarity>(NeutronFlowPolarity::class) {
    override val default: NeutronFlowPolarity = NeutronFlowPolarity(reversed = false)
  }
}

class NeutronFlowPolarityOverride<W>(
  val wrapped: W,
  val polarity: NeutronFlowPolarity
) : Compatible {
  override val compatibilityKey: String = Compatible.keyFor(wrapped)
}

object NeutronFlowPolarityViewFactory : ViewFactory<NeutronFlowPolarityOverride<*>>
by DecorativeViewFactory(
    type = NeutronFlowPolarityOverride::class,
    map = { override, env ->
      Pair(override.wrapped, env + (NeutronFlowPolarity to override.polarity))
    }
)

To make a decorator type that customizes View initialization:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
class WithTutorialTips<W>(val wrapped: W) : Compatible {
  override val compatibilityKey: String = Compatible.keyFor(wrapped)
}

object WithTutorialTipsViewFactory : ViewFactory<WithTutorialTips<*>>
by DecorativeViewFactory(
    type = WithTutorialTips::class,
    map = { withTips -> withTips.wrapped },
    viewStarter = { view, doStart ->
      TutorialTipRunner.run(view)
      doStart()
    }
)

To make a decorator type that adds pre- or post-processing to View updates:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
class BackButtonScreen<W : Any>(
   val wrapped: W,
   val override: Boolean = false,
   val onBackPressed: (() -> Unit)? = null
) : Compatible {
  override val compatibilityKey: String = Compatible.keyFor(wrapped)
}

object BackButtonViewFactory : ViewFactory<BackButtonScreen<*>>
by DecorativeViewFactory(
    type = BackButtonScreen::class,
    map = { outer -> outer.wrapped },
    doShowRendering = { view, innerShowRendering, outerRendering, viewEnvironment ->
      if (!outerRendering.override) {
        // Place our handler before invoking innerShowRendering, so that
        // its later calls to view.backPressedHandler will take precedence
        // over ours.
        view.backPressedHandler = outerRendering.onBackPressed
      }

      innerShowRendering.invoke(outerRendering.wrapped, viewEnvironment)

      if (outerRendering.override) {
        // Place our handler after invoking innerShowRendering, so that ours wins.
        view.backPressedHandler = outerRendering.onBackPressed
      }
    })

Parameters

androidJvm

map

called to convert instances of OuterT to InnerT, and to allow ViewEnvironment to be transformed.

viewStarter

An optional wrapper for the function invoked when View.start is called, allowing for last second initialization of a newly built View. See ViewStarter for details.

doShowRendering

called to apply the ViewShowRendering function for InnerT, allowing pre- and post-processing. Default implementation simply uses map to extract the InnerT instance from OuterT and makes the function call.

Constructors

DecorativeViewFactory [androidJvm] fun <OuterT : Any, InnerT : Any> DecorativeViewFactory(type: KClass<OuterT>, map: (OuterT) -> InnerT, viewStarter: ViewStarter? = null, doShowRendering: (view: View, ViewShowRendering<InnerT>, OuterT, env: ViewEnvironment) -> Unit = { _, innerShowRendering, outerRendering, viewEnvironment ->
innerShowRendering(map(outerRendering), viewEnvironment)
})Convenience constructor for cases requiring no changes to the ViewEnvironment.
DecorativeViewFactory [androidJvm] fun <OuterT : Any, InnerT : Any> DecorativeViewFactory(type: KClass<OuterT>, map: (OuterT, ViewEnvironment) -> Pair<InnerT, ViewEnvironment>, viewStarter: ViewStarter? = null, doShowRendering: (view: View, ViewShowRendering<InnerT>, OuterT, env: ViewEnvironment) -> Unit = { _, innerShowRendering, outerRendering, viewEnvironment ->
val (innerRendering, processedEnv) = map(outerRendering, viewEnvironment)
innerShowRendering(innerRendering, processedEnv)
})called to convert instances of OuterT to InnerT, and to allow ViewEnvironment to be transformed.

Functions

Name Summary
buildView [androidJvm]
Content
open override fun buildView(initialRendering: OuterT, initialViewEnvironment: ViewEnvironment, contextForNewView: Context, container: ViewGroup?): View
More info
Returns a View ready to display initialRendering (and any succeeding values) via View.showRendering.


Properties

Name Summary
type [androidJvm] open override val type: KClass<OuterT>