Best Practices from Oracle Development's A‑Team

ADF Mobile - Browsing Using Swipe Actions


Using swipe actions to browse through a set of data or images is a common user interface pattern on mobile devices. This article explains a simple technique to add support for these swipe actions to your ADF Mobile pages in a declarative way. As part of this technique you will also learn how to define an ADF Mobile skin addition to set custom styles for ADF Mobile user interface controls.

Main Article

The use case that we want to implement is browsing through a set of department records. We start with building the BrowseDepartments page by dragging and dropping our departments collection from the data control palette as ADF Mobile Form. Then we drag and drop the Previous and Next operations as ADF Mobile Button. When deploying and running the application, the page will look like this:


Now, we want to remove the Previous and Next buttons and allow the user to swipe right and swipe left to browse through the departments. ADF Mobile provides two listeners that can listen for swipe actions: the <amx:setPropertyListener> and the <amx:actionListener> elements. As the names suggest the first element can be used to set a property in a memory scope, a managed bean or to set the value on a value binding as defined in the page definition. The second element can be used to perform an action upon swiping, which is what we are looking for.

Now, try to drag and drop the Action Listener from the component palette inside the <amx:panelFormLayout>. You will notice that this operation is not allowed. Currently, ADF Mobile only supports these listener elements on the <amx:commandButton> element and on the <amx:listItem> inside an <amx:listView> element. It is not possible to add the listeners inside any other layout container element such as panel form layout, panel group layout, table layout, row layout or cell format.

To work around this limitation, we enclose the <amx:panelFormLayout> within a dummy list view with one list item:

  • Drag and drop the List View from the component palette onto the page, just below the <amx:panelFormLayout>.
  • In the Create List View dialog that pops up, leave the Bind Data checkbox unchecked and simply click OK.
  • Remove the <amx:outputText> inside the <amx:listItem> and we drag and drop our existing <amx:panelFormLayout> using the structure pane inside the <amx:listItem>.
  • Drag and drop two action listeners inside the <amx:listItem>. The first action listener has the type property set to swipeLeft and the binding property set to the same value as the actionListener property of the Next button. The second action listener has the type property set to swipeRight and the binding property set to the same value as the actionListener property of the Previous button.

After we removed the Previous and Next buttons, the page source should look like this:

<amx:panelPage id="pp1">   <amx:facet name="header">     <amx:outputText value="Department" id="ot1"/>   </amx:facet>   <amx:listView var="row" id="lv1">     <amx:listItem showLinkIcon="false" id="li1">       <amx:panelFormLayout id="pfl1">         <amx:inputText value="#{bindings.id.inputValue}" label="#{bindings.id.hints.label}" id="it2"/>         <amx:inputText value="#{bindings.name.inputValue}" label="#{bindings.name.hints.label}" id="it1"/>         <amx:inputText value="#{bindings.location.inputValue}" label="#{bindings.location.hints.label}" id="it3"/>       </amx:panelFormLayout>       <amx:actionListener binding="#{bindings.Next.execute}" id="al1" type="swipeLeft"/>       <amx:actionListener binding="#{bindings.Previous.execute}" id="al2" type="swipeRight"/>     </amx:listItem>   </amx:listView> </amx:panelPage>

If we deploy and run the application, we can nicely swipe right and swipe left to browse through the departments. However, by adding the dummy list view, the layout of the page has slightly changed, The white background of the list view is visible as we can see below.


Making the Surrounding List View Invisible

To make the surrounding list view invisible to the user we can add the following inlineStyle properties to the list view and list item elements:

<amx:listView var="row" id="lv1" inlineStyle="border-style:none; background-color:transparent;">   <amx:listItem showLinkIcon="false" id="li1" inlineStyle="border-style:none;">     <amx:panelFormLayout id="pfl1">

If we now deploy and run the application again, there no longer seems to be a visual difference with the original page that did not have the dummy list view. However, if you tap on one of the fields to edit it, you will see that the panel form layout is now surrounded by a blue chrome, caused by the selection of the dummy list item that also took place when we tapped inside one of the department items.


This selection is defined in the ADF Mobile stylesheet associated with the default skin. We can define a so-called skin addition to fix this. See the section Skinning ADF Mobile Applications in the ADF Mobile Developers Guide for more info. In a skin addition we can define a cascading stylesheet (CSS) that contains custom styles that should be applied to ADF Mobile user interface controls. This also allows us to get rid of the inline styles and use the cleaner approach of defining a style class instead.

The first step is to create a new CSS file in the ApplicationController project of out mobile application.You can do this by invoking the New gallery, and under Web Tier, select HTML -> CSS File. You can remove the default content that JDeveloper adds to the new CSS file. Before we add the appropriate styles to the CSS file, we first define a skin addition to ensure our CSS file will be picked up at runtime. To do this, open the adfmf-skins.xml file, located in the META-INF directory of your ApplicationController project. Then drag and drop skin-addition from the component palette onto this file. Specify mobileFusionFx as the skin id, and select the CSS file you just created to set the style sheet property.


After you clicked OK, the adfmf-skins.xml file should look like this:

<?xml version="1.0" encoding="UTF-8" ?> <adfmf-skins xmlns="http://xmlns.oracle.com/adf/mf/skin">   <skin-addition id="s1">     <skin-id>mobileFusionFx</skin-id>     <style-sheet-name>css/mystyles.css</style-sheet-name>   </skin-addition> </adfmf-skins>

To make the list view invisible, we need to define the following styles in our CSS file:

.amx-listView.invisible {    border-style:none;    background-color:transparent;    border-bottom:none; } .amx-listView.invisible .amx-listItem {   border-bottom: none;   border-style:none; } .amx-listView.invisible .amx-listItem.amx-listItem-selected {   background-color:transparent;   border-bottom: none; }

To apply these styles to our list view, we need to set the styleClass property of the <amx:listView> element to invisible. The inlyStyle property settings are no longer needed. 

    <amx:listView var="row" id="lv1" styleClass="invisible">       <amx:listItem showLinkIcon="false" id="li1">

As you can see, we use the styleClass property as a marker in our CSS file. Without this marker, all list views in our mobile application would have become invisible.

You might wonder how we figured out the ADF Mobile style selectors as there is no skin editor for ADF Mobile style sheets.The easiest way is to inspect the default style sheets amx.css and amx-v1.1.css. These files reside in the www\css directory. To access this directory, you must first deploy an ADF Mobile application to a simulator or device and then traverse to the deploy directory (for example, C:\JDeveloper\mywork\application name\deploy). The www\css directory resides within the platform-specific artifacts generated by the deployment. For iOS deployments, the directory is located within the temporary_xcode_project directory. For Android deployments, this directory is located in the assets directory of the Android application package (.apk) file.

You can download the sample JDeveloper application here.

Be the first to comment

Comments ( 0 )
Please enter your name.Please provide a valid email address.Please enter a comment.CAPTCHA challenge response provided was incorrect. Please try again.Captcha

Recent Content