Thursday Oct 31, 2013

Responsive Design for your ADF Faces Web Applications

Responsive web applications are a common pattern for designing web pages that adjust their UI based on the device that access them. With the increase in the number of ADF applications that are being accessed from mobile phones and tablet we are getting more and more questions around this topic.

Steven Davelaar wrote a comprehensive article covering key concepts in this area that you can find here. The article focuses on what I would refer to as server adaptive application, where the server adapts the UI it generates based on the device that is accessing the server.

However there is one more technique that is not covered in that article and can be used with Oracle ADF - it is CSS manipulation on the client that can achieve responsive design. I'll cover this technique in this blog entry. The main advantage of this technique is that the UI manipulation does not require the server to send over a new UI when a change is needed. This for example allows your page to change immediately when you change the orientation of your device.

(By the way this example was developed for one of the seminars in the upcoming Oracle ADF OTN Virtual Developer Day).

In the demo that you'll see below you'll see a single page that changes the way it is displayed based on the orientation of the device. Here is the page with the tablet in landscape and portrait:



To achieve this I'm using a CSS media query in my page template that changes the display property of a couple of style classes that are used in my page.

The media query has this format:

@media screen and (max-width:700px) {
            .narrow {
                display: inline;
            }
            .wide {
                display: none;
            }
            .adjustFont {
                font-size: small;
            }
            .icon-home {
                font-size: 24px;
            }
        }

This changes the properties of the same styleClasses that are defined in my application's skin.

Here is a quick demo video that shows you the full application and explains how it works.

Update - since running this demo I found out that in 12.1.2 you get better results if everything relating to the style is defined just in your template and not spread in your skin file too (as shown in the video)

So For those looking to replicate this, here are the basic files:

pageTemplate:

<?xml version='1.0' encoding='UTF-8'?>
<af:pageTemplateDef xmlns:af="http://xmlns.oracle.com/adf/faces/rich" var="attrs" definition="private"
                    xmlns:afc="http://xmlns.oracle.com/adf/faces/rich/component">
    <af:xmlContent>
        <afc:component>
            <afc:description>A template that will work on phones and desktop</afc:description>
            <afc:display-name>ResponsiveTemplate</afc:display-name>
            <afc:facet>
                <afc:facet-name>main</afc:facet-name>
            </afc:facet>
        </afc:component>
    </af:xmlContent>
    <meta name="viewport" content="width=device-width, initial-scale=1"/>
    <af:resource type="css">


.wide {
    display: inline;
}

.narrow {
    display: none;
}

.adjustFont {
    font-size: large;
}
.icon-home {
        font-family: 'UIShellUGH';
    -webkit-font-smoothing: antialiased;
        font-size: 36px;
        color: #ffa000;
}
@media screen and (max-width:700px) {
            .narrow {
                display: inline;
            }
            .wide {
                display: none;
            }
            .adjustFont {
                font-size: small;
            }
            .icon-home {
                font-size: 24px;
            }
        }

@font-face {
            font-family: 'UIShellUGH';
            src: url(data:application/x-font-woff;charset=utf-8;base64,d09GRk9UVE8AA..removed code here...AzV6b1g==)format('truetype');
            font-weight: normal;
            font-style: normal;
        }

    </af:resource>
    <af:panelGroupLayout id="pt_pgl4" layout="vertical" styleClass="sizeStyle">
        <af:panelGridLayout id="pt_pgl1">
            <af:gridRow marginTop="5px" height="40px" id="pt_gr1">
                <af:gridCell marginStart="5px" width="100%" marginEnd="5px" id="pt_gc1">
                    <af:panelGroupLayout id="pt_pgl3" halign="center" layout="horizontal">
                        <af:outputText value="h" id="ot2" styleClass="icon-home"/>
                        <af:outputText value="HR System" id="ot3" styleClass="adjustFont"/>
                    </af:panelGroupLayout>
                </af:gridCell>
            </af:gridRow>
            <af:gridRow marginTop="5px" height="auto" id="pt_gr2">
                <af:gridCell marginStart="5px" width="100%" marginEnd="5px" id="pt_gc2" halign="stretch">
                    <af:panelGroupLayout id="pt_pgl2" layout="scroll">
                        <af:facetRef facetName="main"/>
                    </af:panelGroupLayout>
                </af:gridCell>
            </af:gridRow>
            <af:gridRow marginTop="5px" height="20px" marginBottom="5px" id="pt_gr3">
                <af:gridCell marginStart="5px" width="100%" marginEnd="5px" id="pt_gc3">
                    <af:panelGroupLayout id="pt_pgl5" layout="vertical" halign="center">
                        <af:separator id="pt_s1"/>
                        <af:outputText value="Copyright Oracle Corp. 2013" id="pt_ot1" styleClass="adjustFont"/>
                    </af:panelGroupLayout>
                </af:gridCell>
            </af:gridRow>
        </af:panelGridLayout>
    </af:panelGroupLayout>
</af:pageTemplateDef>

Example from the page:

                        <af:gridRow id="gr3">
                            <af:gridCell id="gc7" columnSpan="2">
                                <af:panelGroupLayout id="pgl8" styleClass="narrow">
                                    <af:link text="Menu" id="l1">
                                        <af:showPopupBehavior triggerType="action" popupId="p1" align="afterEnd"/>
                                    </af:link>
                                </af:panelGroupLayout>
                                <af:panelGroupLayout id="pgl7" styleClass="wide">
                                    <af:navigationPane id="np1" hint="buttons">
                                        <af:commandNavigationItem text="Departments" id="cni1"/>
                                        <af:commandNavigationItem text="Employees" id="cni2"/>
                                        <af:commandNavigationItem text="Salaries" id="cni3"/>
                                        <af:commandNavigationItem text="Jobs" id="cni4"/>
                                        <af:commandNavigationItem text="Services" id="cni5"/>
                                        <af:commandNavigationItem text="Support" id="cni6"/>
                                        <af:commandNavigationItem text="Help" id="cni7"/>
                                    </af:navigationPane>
                                </af:panelGroupLayout>
                            </af:gridCell>
                        </af:gridRow>

I placed a workspace with this sample here. Run the sample.jsf page in the viewController project.

Monday Jul 22, 2013

Tablet support in ADF Faces with 12c

I blogged before about the support for tablet and touch device rendering with ADF Faces. Release 12c brings together features that were introduced in previous patches (such as 11.1.1.7) into a single line of code and even adds more features in this area.

To show you what ADF Faces does automatically for you, I re-recorded the interaction with the houses demo that I showed here, but this time on an iPad.

Things to note:

  • Switching from stretch to flow layout (eliminates scroll bars and allow swipe scroll)
  • Table pagination instead of scroll bars
  • HTML5 rendering for data visualization components instead of Flash
  • Drag and drop and tap and hold support on device
  • Swipe support on objects such as cards in a hierarchy viewer
  • Maximize area support
  • New tablet style UI components (Springboard and list view for example)

 It's a single application that runs on both the regular and mobile browser.

The only thing I needed to do is use an EL for two properties (maximize and dimensionsFrom) on the top containers in the page that will switch the whole page to do flow layout on touch devices. You would usually use this in your page template for the application.

The code I use is:

    <af:document title="index.jsf" id="d1"
                 maximize="#{adfFacesContext.agent.capabilities['touchScreen'] eq 'none' ? true : false}">
        <af:form id="f1">
            <af:panelStretchLayout id="psl1"
                                   dimensionsFrom="#{adfFacesContext.agent.capabilities['touchScreen'] eq 'none'  ?'parent' : 'children'  }">

Here's the video:


Friday May 10, 2013

Simpler Development with the new List ADF Faces component in 11.1.1.7

A new component that showed up in the JDeveloper 11.1.1.7 release is the af:listView component. This component will become more and more popular as more people target tablet devices with ADF Faces UI. The component allows you to create a scrollable list from a collection of data, and it also does fetching with ranges so you don't get too much network traffic. If you ever used a contacts list on a smart phone you'll recognize the list view source of inspiration - check out the runtime demo of the component here.

The component was actually backported into 11.1.1.7 from the 12c version - and while in the 12c version of JDeveloper there is better design time support for adding and binding a listview to a page, in the current release the work will mostly be manual.

However, for the lazy developer there are some shortcuts you can take to create the list component faster.

Here is a short video that shows you how to leverage an existing table component on your page to make the creation of the list component easier and with more functionality.

Monday Oct 15, 2012

Adaptive Layout for ADF Faces on Tablets

In the 11.1.16 version of Oracle ADF we started adding specific features to the ADF Faces components so they'll work better on iPad tablets.

In this entry I'm going to highlight some new capabilities that we have added to the 11.1.2.3 release. (note if you are still on the 11.1.1.* branch - you'll need to wait for 11.1.1.7 to get the features discussed here).

The two key additions in the 11.1.2.3 version compared to the 11.1.1.6 features for iPad support include: pagination for tables and adaptive flow layout.

The pagination for table is self explanatory, basically since iPad don't support scroll bars, we automatically switch the table component to render with a pagination toolbar that allow you to scroll set of records or directly jump to a specific set. See the image below.