カスタム・レンダラについて

ADF UIXのデフォルトのスタイルをオーバーライドする独自のカスタム・ルック&フィールを作成すると、UIXアプリケーションの外観を大幅に変更できます。しかし、スタイルとアイコンのカスタマイズでは不十分な場合もあります。UIXコンポーネントの外観全体を制御する場合は、カスタム・レンダラを記述する必要があります。

レンダラは、UIXコンポーネントに関連付けられたコンテンツを生成するためのオブジェクトです。カスタム・コンポーネント用の独自のレンダラ定義の詳細は、「ADF UIX開発者ガイド」の「ADF UIXの拡張」の章を参照してください。このトピックでは、UIXのビルトイン・コンポーネント用のレンダラを置き換える方法を説明します。

カスタム・ルック&フィール用のレンダラを作成する場合は、レンダラを実装する2通りの方法から選択します。つまり、レンダラは、JavaクラスまたはUIX XMLテンプレート(UIT)として実装できます。

Javaベースのレンダラは、最大の柔軟性を提供しますが、Javaコードを記述する必要があります。これはルック&フィールの実装を行う者すべてが満足するわけではありません。Javaベースのレンダラを記述する場合にもう1つ注意することは、JavaServer Facesが採用されるとレンダラAPI自体が変更されている可能性がきわめて高いことです。現在、UIXでは独自のレンダラ・インタフェースを定義しています。今後、レンダラの概念をJavaServer Facesで定義する予定です。Javaベースのレンダラの実装は、JavaServer Faces API用に書き換えが必要になる場合があります。一方、テンプレートベースのレンダラは、多くの場合に移植可能です(少なくとも、より自動化された移行パスがあります)。

Javaベースのレンダラの実装

望ましいページ・レイアウトはほとんどのケースでサイトごとに異なるため、カスタム・レンダラを最も必要とするコンポーネントはおそらくpageLayoutコンポーネントとなります。次にpageLayoutレンダラの実装を変更する簡単な例を示します。簡潔にするため、ここではpageLayoutの名前付きの子である、tabsとpageHeaderの2つのみを扱います。pageLayoutコンポーネントは他にもこのサンプルでは扱わない多くの名前付きの子と属性をサポートしているため、実際に動作するpageLayoutレンダラにはかなり多くの作業が必要となります。

このサンプル用に、ここではpageLayoutを1つのHTML表として実装します。この表は、tabsの行、pageHeaderの行、pageLayoutの他の索引付けされた子の行の3行で構成されます。以下に、このレイアウトを実装するJavaベースのサンプル・レンダラを示します。


Example:

import java.io.IOException;
import oracle.cabo.ui.ElementRenderer;
import oracle.cabo.ui.RenderingContext;
import oracle.cabo.ui.UIConstants;
import oracle.cabo.ui.UINode;
import oracle.cabo.ui.io.OutputMethod;

// A subclass of ElementRenderer which implements a custom
// pageLayout.
public class PageLayoutRenderer extends ElementRenderer
{
  /**
   * Override of ElementRenderer.getElementName()
   */
  protected String getElementName(
    RenderingContext context,
    UINode           node
    )
  {
    // ElementRenderer automatically renders the start/end
    // tags for the element that is returned by getElementName().
    // Our custom pageLayout renders itself in an HTML table
    // element, so that is what we return
    return "table";
  }

  /**
   * Override of ElementRenderer.renderAttributes().
   */
  protected void renderAttributes(
    RenderingContext context,
    UINode           node
    ) throws IOException
  {
    // renderAttributes() is used to render attribute on the
    // element that is returned by getElementName(). Let's
    // remove all spacing/padding/borders from our layout table.
    OutputMethod out = context.getOutputMethod();
    out.writeAttribute("border", "0");
    out.writeAttribute("cellpadding", "0");
    out.writeAttribute("cellspacing", "0");

    // Call super.renderAttributes() just in case the
    // super class has anything to add
    super.renderAttributes(context, node);
  }

  /**
   * Override of ElementRenderer.prerender()
   */
  protected void prerender(
    RenderingContext context,
    UINode           node
    ) throws IOException
  {
    // First, call super.prerender() so that the
    // "table" element will be started.
    super.prerender(context, node);

    // Now, we render some additional contents in our table.
    // Retrieve the OutputMethod.
    OutputMethod out = context.getOutputMethod();

   // Render the tabBar named child in its own table cell
    out.startElement("tr");
    out.startElement("td");

   // Use BaseRenderer.renderNamedChild() to do the actual rendering
   renderNamedChild(context, node, UIConstants.TABS_CHILD);

   out.endElement("td");
   out.endElement("tr");

   // Render the pageHeader named child in its own table cell
   out.startElement("tr");
   out.startElement("td");

   // Use BaseRenderer.renderNamedChild() to do the actual rendering
   renderNamedChild(context, node, UIConstants.PAGE_HEADER_CHILD);

   out.endElement("td");
   out.endElement("tr");
  }

  /**
   * Override BaseRenderer.renderContent()
   */
  public void renderContent(
    RenderingContext context,
    UINode           node)
    throws IOException
  {
    // renderContent() normally just renders all indexed children.
    // However, since we are rendering our contents inside of an
    // HTML table, we need to override these method to place the
    // indexed children inside of their own table row

    // Retrieve the OutputMethod and start the table row/cell
    OutputMethod out = context.getOutputMethod();
    out.startElement("tr");
    out.startElement("td");

    // Render the contents
    super.renderContent(context, node);

    // Close up the contents table cell/row
    out.endElement("td");
    out.endElement("tr");
  }
}    
カスタム・レンダラを構築したら、これをコンパイルし、クラスパスにレンダラ・クラスをインストールする必要があります(たとえば、WebアプリケーションのWEB-INF/クラス・ディレクトリの下に)。使用するレンダラを指定するには、それをルック・アンド・フィール構成ファイルに登録する必要があります。たとえば、上のレンダラがorg.example.laf.customパッケージにインストールされたとすると、次に示すように<renderer>要素を使用してこのレンダラを登録できます。

...
  <renderers>
    <renderer name="ui:pageLayout">
      <class name="org.example.laf.custom.PageLayoutRenderer"/>
    </renderer>
  </renderers>
...    

カスタム・ルック・アンド・フィールが優先ルック・アンド・フィールとして選択された場合は、カスタム・レンダラ・クラスが自動的にインスタンス化され、UIXのビルトイン・レンダラのかわりに使用されます。

テンプレートベースのレンダラの実装

Javaベースのカスタム・レンダラは、大きな柔軟性を提供しますが、ルック・アンド・フィールを実装する者の多くはJavaコードの記述を避けようとします。テンプレートベースのレンダラは、宣言によるソリューションを好む実装者のための方法です。ADF UIXでは、UIX XMLテンプレート・ファイルをJavaクラスのかわりにレンダラとして登録できます。UIX XMLテンプレート・ファイルがレンダラとして登録されると、このテンプレートは通常のようにページ作成者が直接参照することはありません。そのかわりにUIXで使用され、対応するコンポーネントをレンダリングします。

次のサンプルでは、UIX XMLテンプレートを使用して書き換えたpageLayoutレンダラを示します。


Example:

<?xml version="1.0" encoding="UTF-8"?>
<templateDefinition xmlns="http://xmlns.oracle.com/uix/ui"
                    xmlns:ui="http://xmlns.oracle.com/uix/ui"
                    xmlns:demo="http://www.example.org/demo/templates"
                    targetNamespace="http://www.example.org/demo/templates"
                    localName="pageLayout">
  <content>

    <!-- We place the pageLayout contents in a tableLayout component -->
    <tableLayout>
      <contents>

        <!-- Render the tabs named child in its own row/cell -->
        <rowLayout>
          <contents>
            <cellFormat>
              <contents>
                <rootChild name="tabs"/>
              </contents>
            </cellFormat>
          </contents>
        </rowLayout>

        <!-- Render the pageHeader named child in its own row/cell -->
        <rowLayout>
          <contents>
            <cellFormat>
              <contents>
                <rootChild name="pageHeader"/>
              </contents>
            </cellFormat>
          </contents>
        </rowLayout>

        <!-- Render the pageLayout contents in its own row/cell -->
        <rowLayout>
          <contents>
            <cellFormat>
              <contents>
                <rootChild name="contents"/>
              </contents>
            </cellFormat>
          </contents>
        </rowLayout>
      </contents>
    </tableLayout>
  </content>
</templateDefinition>    

テンプレートベースのレンダラは、通常のUIX XMLテンプレートと同じ構造です。たとえば、名前付きの子は<rootChild>要素を使用して参照されます。通常のUIX XMLテンプレートで使用できる要素や属性は、テンプレートベースのレンダラでも使用できます。

テンプレートベースのレンダラも、Javaベースのレンダラと同様にルック・アンド・フィール構成ファイルに登録する必要があります。次のサンプルに、上のテンプレートベースのレンダラがWebアプリケーション・ルートの下のtemplates/laf/customディレクトリにインストールされた場合に、このレンダラを登録する方法を示します。


...
  <renderer name="ui:pageLayout">
    <template name="templates/laf/custom/pageLayout.uit"/>
  </renderer>
...    

レンダラを実装するためのもう1つの便利な方法は、テンプレート内に任意のHTMLコンテンツを埋め込むことです。次に示すように、HTMLに切り替えることで上のテンプレートを大幅に簡素化できます。


Example:

<?xml version="1.0" encoding="UTF-8"?>
<templateDefinition xmlns="http://xmlns.oracle.com/uix/ui"
                    xmlns:ui="http://xmlns.oracle.com/uix/ui"
                    xmlns:demo="http://www.example.org/demo/templates"
                    targetNamespace="http://www.example.org/demo/templates"
                    localName="pageLayout">
  <content>

    <!-- Place the pageLayout contents in an HTML table element -->
    <table xmlns="http://www.w3.org/TR/REC-html40"
           cellpadding="0" cellspacing="0" border="0">

      <!-- Render the tabs named child in its own row/cell -->
      <tr><td><ui:rootChild name="tabs"/></td></tr>

      <!-- Render the tabs named child in its own row/cell -->
      <tr><td><ui:rootChild name="pageHeader"/></td></tr>

      <!-- Render the pageLayout contents in its own row/cell -->
      <tr><td><ui:rootChild name="contents"/></td></tr>

    </table>

  </content>

</templateDefinition>    

上の例では、ネームスペースをhttp://www.w3.org/TR/REC-html40demoTmpsに設定することによって任意のHTML要素を使用できるようになっていることに注意してください。これで、すべてのUIXコンポーネントに必要な<contents>要素の使用を避けることが可能になります。<rootChild>などの要素のネームスペースの接頭辞を明示的に指定すれば、これらの要素はなお使用することができます。


カスタム・スタイルシートについて
カスタム・アイコンについて

カスタム・ルック・アンド・フィールの作成
ADF UIXページの操作
Webアプリケーション設計ツールの使用

 

Copyright © 1997, 2004, Oracle. All rights reserved.