jsf

Blurry Graphics in ADF Faces

Posted on Updated on

Ever since Apple introduced the Retina Display in 2010, modern devices have changed to display content at twice (@2x), three times (@3x), four times (@4x) [or even fractions in-between] the resolution that we have been used to in the past.

For app developers using bitmap graphics, this can be a bit of a nightmare to support. You have to generate graphics at multiple resolutions and change your application to reference different sizes of graphics. Unless you are using photographic content, you may find it easier to deal with SVG (vector graphic) images instead.

In ADF Faces applications, there are at least 3 categories of ways to display images:

  1. Image components
  2. Components that have an image somewhere inside of it (and that don’t offer a style attribute explicitly for that image)
  3. CSS background-image styles

blurry-images

SVG

For all 3 use cases, simply use the .svg file as you have been accustomed to using for .png files. Just make sure the graphic was well-designed to look good on an @1x display if legacy support is important to you.

PNG (or other bitmap graphic)

For use case 1, you specify your image in the “source” attribute then the dimensions in the “inlineStyle” attribute.

For use case 2, you specify your image in the appropriate image attribute, e.g. “icon” and specify a marker “styleClass” that you’ll need to make a style block definition for (e.g. via an af:resource tag). This block will use that marker then space then “IMG” for its selector and then in the body of the block, specify the width and height.

For use case 3, you are dealing with CSS styles (e.g. in an af:resource). Since browser support is not universal, you will need to specify 3 kinds of selectors: (a) the default fallback for legacy browsers–where you define your @1x graphic, (b) the WebKit @2x override, (c) the modern @2x override. You can make additional blocks for @3x, @4x, etc. (You may optionally use this technique to hide/show specific component instances for use cases 1 & 2 too if you really want your app to display resolution-specific graphics.)

Sample code

<?xml version='1.0' encoding='UTF-8'?>
<jsp:root xmlns:jsp="http://java.sun.com/JSP/Page" version="2.1"
  xmlns:f="http://java.sun.com/jsf/core"
  xmlns:af="http://xmlns.oracle.com/adf/faces/rich"
  xmlns:trh="http://myfaces.apache.org/trinidad/html">
  <jsp:directive.page contentType="text/html;charset=UTF-8"/>
  <f:view>
    <af:document id="d1" title="Blurry Graphics" inlineStyle="padding:10px;">
      <f:facet name="metaContainer">
        <af:resource type="css">
          /* Dimensions for bitmap graphics on components that don't have
             style attributes for internal image elements. */
          .MyIconHolder IMG {
            width: 24px;
            height: 24px;
          }
          /* Example of background-image graphics */
          .MyBackgroundPNGImage {
            background-repeat: no-repeat;
            width: 24px;
            height: 24px;
            background-image: url(images/image@1x.png);
          }
          @media only screen and (-webkit-min-device-pixel-ratio: 2) {
            .MyBackgroundPNGImage {
              background-image: url('images/image@2x.png');
              -webkit-background-size: 24px 24px;
            }
          }
          @media only screen and (min-resolution: 2dppx) {
            .MyBackgroundPNGImage {
              background-image: url('images/image@2x.png');
              background-size: 24px 24px;
            }
          }
          .MyBackgroundSVGImage {
            background-repeat: no-repeat;
            width: 24px;
            height: 24px;
            background-image: url(images/image.svg);
          }
        </af:resource>
      </f:facet>
      <af:form id="f1">
        <trh:tableLayout id="tl1" borderWidth="1">
          <trh:rowLayout id="rl1">
            <trh:cellFormat id="cf1" header="true">
              <af:outputText id="ot1" value="Use Case"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf2" header="true">
              <af:outputText id="ot2" value="@1x PNG"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf3" header="true">
              <af:outputText id="ot3" value="@2x PNG"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf4" header="true">
              <af:outputText id="ot4" value="SVG"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl2">
            <trh:cellFormat id="cf5" halign="center">
              <af:outputText id="ot5" value="af:image"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf6" halign="center">
              <af:image id="i1" source="/images/image@1x.png"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf7" halign="center">
              <af:image id="i2" source="/images/image@2x.png"
                inlineStyle="width:24px;height:24px;"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf8" halign="center">
              <af:image id="i3" source="/images/image.svg"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl3">
            <trh:cellFormat id="cf9" halign="center">
              <af:panelGroupLayout id="pgl1" layout="vertical">
                <af:outputText id="ot6" value="af:commandToolbarButton"/>
                <af:outputText id="ot7" value="(no style attribute for dimensions)"/>
              </af:panelGroupLayout>
            </trh:cellFormat>
            <trh:cellFormat id="cf10" halign="center">
              <af:commandToolbarButton id="ctb1" icon="/images/image@1x.png"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf11" halign="center">
              <af:commandToolbarButton id="ctb2" icon="/images/image@2x.png"
                styleClass="MyIconHolder"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf12" halign="center">
              <af:commandToolbarButton id="ctb3" icon="/images/image.svg"/>
            </trh:cellFormat>
          </trh:rowLayout>
          <trh:rowLayout id="rl4">
            <trh:cellFormat id="cf13" halign="center">
              <af:panelGroupLayout id="pgl2" layout="vertical">
                <af:outputText id="ot8" value="af:panelGroupLayout"/>
                <af:outputText id="ot9" value="(background-image styling)"/>
              </af:panelGroupLayout>
            </trh:cellFormat>
            <trh:cellFormat id="cf14" halign="center" columnSpan="2">
              <af:panelGroupLayout id="pgl3" layout="vertical"
                styleClass="MyBackgroundPNGImage"/>
            </trh:cellFormat>
            <trh:cellFormat id="cf16" halign="center">
              <af:panelGroupLayout id="pgl4" layout="vertical"
                styleClass="MyBackgroundSVGImage"/>
            </trh:cellFormat>
          </trh:rowLayout>
        </trh:tableLayout>
      </af:form>
    </af:document>
  </f:view>
</jsp:root>

Accessing Managed Beans from Java

Posted on

The following link shows a helpful article comparing alternate ways of using Java to programmatically retrieve an ADF Faces or JSF managed bean.  In other words, this is how to evaluate EL in Java code.

http://java.sys-con.com/node/1984284

Creating a panelGridLayout or tableLayout structure

Posted on Updated on

It may be tempting to go crazy with panelGroupLayout components in ADF Faces and ADF Mobile. The panelGroupLayout is not the universal hammer. In many cases, you will have a simpler structure (easier to maintain, more predictable, faster performing, more flexible) if you build your structure using a panelGridLayout or tableLayout instead.

structure

When you are given a mock-up of what the application should look like, you may not know how to break it down into something simple. Either print out the design on a piece of paper or open it up in a graphics program where you can draw some lines.

  1. Draw vertical lines representing potential column divisions (red)
  2. Draw horizontal lines for potential row divisions (green)
  3. Now that you have a basic grid structure, use a different color (yellow) to draw x marks where you see cells that need to span multiple columns or rows:
    Initial set of lines
  4. You may find that your column lines really don’t make sense (in this case, the 2 middle columns had no cells in them that didn’t need to span into a nearby column. This is an indication that there probably ought to be 2 separate grids or tables.  Use a new color (magenta) to draw a line where the division makes sense and repeat the process again:
    Refined lines

Now you can go back to coding your gridRow/gridCell or rowLayout/cellFormat components because you can visually see where the content goes and where you need to use a special columnSpan or rowSpan. As an added bonus, you now have the ability to specify the sizes for your cells as well as the horizontal and vertical alignments of your cells–something panelGroupLayout would not allow you to control.

Final structure

Notice that the labels and fields of grid 2 (columns 1 and 2) are showing separate components. This is done so that there can be matching horizontal alignment among the fields of the two rows. If these were input or select components, you would need to use simple=”true” (to hide the built-in label) and then use separate outputLabel components that reference them.

While we are only using consecutive grids in the example discussed in this article. You might come across a need to nest a grid inside of another grid. Do not excessively nest panelGridLayout nor tableLayout components (if you have 3 or more deep, consider a re-evaluation of your structure). You may find it helpful if someone else reviews your structure. Your goal should be to create something simple.

ADF Client Performance Optimization Tips

Posted on

If you are noticing client-side performance issues in your ADF Faces application and must support legacy browsers like Internet Explorer 7 and Internet Explorer 8, there are many techniques available to help optimize your application for these browsers:

  1. If you use af:region and the jsff page fragment files have more than 1 root component, optimize it by arranging these components with a single root component. For example, if you want your region contents to stretch, you might have one visible content component and a series of popup components, put the visible content component inside of a “center” facet of an af:panelStretchLayout and put all of those popups in the “bottom” facet but also make sure to assign bottomHeight=”0px”. If you don’t want the contents to stretch, simply wrap these components with an af:panelGroupLayout layout=”vertical”.
  2. Avoid using a af:panelStretchLayout where topHeight, bottomHeight, startWidth, or endWidth is set to “auto”.
  3. Minimize uses of af:panelAccordion in discloseMany=”true” mode if possible.
  4. Minimize use of components that provide overflow popups, e.g. af:panelAccordion, af:panelTabbed, af:toolbar, af:breadCrumbs, af:menuBar. If you have to use these components, make sure that your target screen size can accommodate the content without having to invoke overflow.
  5. Minimize use of components that provide custom title text truncation, e.g. af:panelHeader and af:showDetailHeader. If you have to use these components, make sure that your target screen size can accommodate the title text without having to truncate.
  6. Minimize use of af:carousel, af:table, af:tree, af:treeTable.
  7. Avoid complex user interfaces. Users will struggle to process complex application structures. Legacy browsers will struggle with processing of complex content. Keep the number of tabs simple (use less than 10). Keep the number of columns in a table small (use less than 10).
  8. Finally, don’t ignore the warnings that JDeveloper gives you.

BIDI via EL in ADF Faces

Posted on

At some point, you may have an inlineStyle whose value is BIDI sensitive; in LTR (left-to-right) mode, you may want a “left” style but in RTL (right-to-left) mode, you may want a “right” style.  You don’t have to write a managed bean to give you the corresponding style, you can use EL (expression language).

Here’s an example assigning a padding for the “start” side of 10px:

inlineStyle="padding-#{adfFacesContext.rightToLeft?'right':'left'}:10px;"
See oracle.adf.view.rich.context.AdfFacesContext for other properties.

UIInstructions Polluting your JSF 2 Component Tree

Posted on Updated on

If you are ever debugging a JSF 2 application, are seeing some “UIInstructions” components mysteriously polluting the component tree, and want to get rid of them (e.g. breaking desired sole-child configurations for layout geometry reasons), this tip is for you…

These UIInstructions components are likely due to the presence of an HTML DOCTYPE (or other content) appearing in one or more of your JSF fragment files. These fragment files are likely missing a ui:composition wrapper.

More info on why you might want the HTML DOCTYPE (or other content):
http://download.oracle.com/javaee/6/javaserverfaces/2.0/docs/pdldocs/facelets/ui/composition.html

Defining an attribute-class for an array of objects

Posted on Updated on

When defining the attributes for an ADF Faces af:pageTemplate or af:declarativeComponent inside of an af:xmlContent, you need to provide an attribute-class definition. This looks something like:

<attribute-class>java.lang.String</attribute-class>

but what if you needed an array of Strings? That has a bit stranger syntax:

<attribute-class>[[Ljava.lang.String;</attribute-class>

Why is this not just “java.lang.String[]”? These attribute-class entries are the result of calling Class.forName.  The Class.forName on an array of objects looks like “[[Lsome.package.SomeClass;”.