Customize how a Questionnaire is displayed
The Structured Data Capture Library provides default UI components and styles to render FHIR Questionnaire resources based on Material Design and the Structured Data Capture Implementation Guide. In practice, you may want to customize how questionnaires look, and this guide explains the two primary ways to do so:
- Adjust the existing components to match the style of the rest of your application
- Create new components to collect information in non-standard ways, e.g. connected devices
Customize styles
The Structured Data Capture Library includes a default theme Theme.Questionnaire
which defines a number of custom attributes used to style questionnaires. For example, questionnaireQuestionTextStyle
defines the style for all question text, and changing it affects all rendered questionnaires. The custom attributes are:
groupHeaderTextAppearanceQuestionnaire
questionnaireQuestionTextStyle
questionnaireSubtitleTextStyle
questionnaireRadioButtonStyle
questionnaireCheckBoxStyle
questionnaireDropDownTextStyle
questionnaireDropdownLayoutStyle
questionnaireTextInputLayoutStyle
questionnaireTextInputEditTextStyle
questionnaireChipStyle
questionnaireDialogTitleStyle
questionnaireDialogButtonStyle
questionnaireAddAnotherAnswerButtonStyle
questionnaireErrorTextStyle
questionnaireButtonStyle
questionnaireSubmitButtonStyle
To customize the styles used to render questionnaires, create a theme with different values for the custom attributes. A simple way to do this is to extend the Theme.Questionnaire
theme and override the attributes you want to change.
For example, to change the appearance of question text, open your project's res/values/styles.xml
file and add a new theme that extends Theme.Questionnaire
, then set the headerTextAppearanceQuestionnaire
attribute to your preferred value:
<style name="Theme.MyQuestionnaire" parent="Theme.Questionnaire">
<item name="questionnaireQuestionTextStyle">
@style/TextAppearance.MaterialComponents.Subtitle2
</item>
</style>
Next, edit your application's default theme, typically in the res/values/themes.xml
file, and add the attribute questionnaire_theme
set to the new theme you just created:
<style name="Theme.MyApplication" parent="Theme.Material3.DayNight.NoActionBar">
...
<item name="questionnaire_theme">@style/Theme.MyQuestionnaire</item>
</style>
Custom Style per Question Item
With this change, you can apply individual custom styles per question item. If a custom style is not mentioned in the question item, the default style will be applied, which is present in the DataCapture module or overridden in the application.
Add a Custom Style Extension to the Question Item
{
"extension": [
{
"url": "https://github.com/google/android-fhir/tree/master/datacapture/android-style",
"extension": [
{
"url": "prefix_text_view",
"valueString": "CustomStyle_1"
},
{
"url": "question_text_view",
"valueString": "CustomStyle_1"
},
{
"url": "subtitle_text_view",
"valueString": "CustomStyle_2"
}
]
}
]
}
Custom Style Extension URL
"https://github.com/google/android-fhir/tree/master/datacapture/android-style"
It identifies extensions for applying the custom style to a given questionnaire item.
Question Item View
prefix_text_view
: Used to show the prefix value of the question item.question_text_view
: Used to show the text value of the question item.subtitle_text_view
: Used to show the instructions of the question item. For more information about supported views, please see the Question Item View.
Custom Style Values
In the above example:
CustomStyle_1
is the custom style for prefix_text_view and question_text_view. CustomStyle_2
is the custom style for subtitle_text_view. Both styles are defined in the application.
Custom Style Attributes
questionnaire_textAppearance
: Specifies the text appearance for the questionnaire text. Example:@style/TextAppearance.AppCompat.Headline
questionnaire_background
: Specifies the background for the view. Example:@color/background_color or #FFFFFF
For more information on custom style attributes, please see the QuestionnaireCustomStyle
Example Custom Styles
<style name="CustomStyle_1">
<item name="questionnaire_textAppearance">@style/CustomTextAppearance_1</item>
</style>
<style name="CustomStyle_2">
<item name="questionnaire_textAppearance">@style/CustomTextAppearance_2</item>
</style>
<style
name="CustomTextAppearance_1"
parent="TextAppearance.Material3.HeadlineLarge"
>
<item name="android:textColor">?attr/colorOnTertiaryContainer</item>
</style>
<style name="CustomStyle_2">
<item
name="questionnaire_textAppearance"
>@style/CustomTextAppearance_2</item>
<item name="questionnaire_background">?attr/colorSurfaceVariant</item>
</style>
The above custom styles are defined in the res/values/styles.xml
of the application.
questionnaire.json with custom style
{
"resourceType": "Questionnaire",
"item": [
{
"linkId": "1",
"text": "Question text custom style",
"type": "display",
"extension": [
{
"url": "https://github.com/google/android-fhir/tree/master/datacapture/android-style",
"extension": [
{
"url": "prefix_text_view",
"valueString": "CustomStyle_1"
},
{
"url": "question_text_view",
"valueString": "CustomStyle_1"
},
{
"url": "subtitle_text_view",
"valueString": "CustomStyle_2"
}
]
}
],
"item": [
{
"extension": [
{
"url": "http://hl7.org/fhir/StructureDefinition/questionnaire-displayCategory",
"valueCodeableConcept": {
"coding": [
{
"system": "http://hl7.org/fhir/questionnaire-display-category",
"code": "instructions"
}
]
}
}
],
"linkId": "1.3",
"text": "Instructions custom style.",
"type": "display"
}
]
} ]
}
Custom questionnaire components
The Structured Data Capture Library uses custom UI components to render questions in a questionnaire. There are predefined components for most question item types so you do not need to do anything special for most questions. However, if you want to render a question in a way not described in the FHIR standard of the SDC implementation guide, you can create a custom component.
Create a custom component
This guide outlines the step-by-step process to create and incorporate custom widgets into FHIR questionnaires using the Android FHIR SDK.
Note: Examples given below are all from the catalog application in this repository. We recommend you try out the application to see these concepts in action.
- Create a layout for the Custom Component
Design an XML layout file to define the visual structure and appearance of your custom widget.
* Example: See this [example location_widget_view.xml](https://github.com/google/android-fhir/blob/master/contrib/locationwidget/src/main/res/layout/location_widget_view.xml).
- Create a
QuestionnaireItemViewHolderFactory
class
Implement a class that extends QuestionnaireItemViewHolderFactory. This class will be responsible for creating and managing the view holder for your custom component.
* Example: Check out this [example LocationWidgetViewHolderFactory](https://github.com/google/android-fhir/blob/master/contrib/locationwidget/src/main/java/com/google/android/fhir/datacapture/contrib/views/locationwidget/LocationWidgetViewHolderFactory.kt#L29).
Within this class:
* Pass the layout resource ID to the constructor.
* Override `getQuestionnaireItemViewHolderDelegate()` to return a `QuestionnaireItemViewHolderDelegate` implementation. This delegate should include:
* `init`: Initializes the `RecyclerView.ViewHolder`.
* `bind`: Binds data to the `RecyclerView.ViewHolder`.
* `displayValidationResult`: Displays validation feedback for user input.
* `setReadOnly`: Configures the UI for read-only mode.
- Create
QuestionnaireItemViewHolderFactoryMatcher
Objects
For each custom ViewHolderFactory
, create a corresponding factory matcher object - QuestionnaireItemViewHolderFactoryMatcher
* Example: Refer to these [matcher examples](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory.kt#L38C15-L45C16).
Each matcher should define:
* `factory`: The custom `ViewHolderFactory` instance.
* `matches`: A predicate function that takes a [`Questionnaire.QuestionnaireItemComponent`](https://hapifhir.io/hapi-fhir/apidocs/hapi-fhir-structures-r4/org/hl7/fhir/r4/model/Questionnaire.QuestionnaireItemComponent.html) and returns `true` if this factory is suitable for rendering that item.
- Create a
QuestionnaireItemViewHolderFactoryMatchersProviderFactory
Create a factory class that implements this interface. It acts as a central registry for your custom widget associations.
* Example: This [example factory class](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/ContribQuestionnaireItemViewHolderFactoryMatchersProviderFactory.kt) demonstrates this.
- Register the Factory in
DataCaptureConfig
In your DataCaptureConfig
object, set the questionnaireItemViewHolderFactoryMatchersProviderFactory
property to your custom factory instance.
* Example: See how this is done in [this code](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/CatalogApplication.kt#L42C5-L47C8).
- Use the Custom Widget in Your Questionnaire Fragment
When building your QuestionnaireFragment
, call the setCustomQuestionnaireItemViewHolderFactoryMatchersProvider
method on the builder, providing the string identifier associated with your custom widget.
* Example: This [usage example](https://github.com/google/android-fhir/blob/master/catalog/src/main/java/com/google/android/fhir/catalog/DemoQuestionnaireFragment.kt#L142C13-L150C23) shows how to set up the fragment.
Localize questionnaires
When rendering your questionnaire, the library will look for the translation extension, and if the lang element matches the application default locale, will use the value of the content element of the extension instead of the text element of the questionnaire item. You can also use the Locale.setDefault()
method to manually set the locale to check against.