OS 5.0的黑莓平台没有提供多页标签栏,下面我们来实现一个。
效果如下图,三个栏目,选择不同的栏目(TabItem),下面的内容不同(Manager)。
标签页是用一个定制的Field TabItem,在paint()方法中根据该Field是focus与否的状态选择显示不同的背景图片。
标签页被选中的时候,调用fieldChangeNotify( 0 )方法通知TabControl窗口需要更换标签页下面的manager显示不同的内容。
代码中用到的三个资源文件:
tabitem_default.png ,注意图片的右边,是有个凹陷的效果
tabitem_selected.png,和上面的图片是相同大小,但是颜色是白色的,右边有个竖线
table_background.png,这张图片将被铺满整条横向的Tab栏目。
详细代码如下:
TabControl.java
TabItem.java
BaseButtonField.java
package cn.rim.samples.tabcontrol;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.decor.Background;
import net.rim.device.api.ui.decor.BackgroundFactory;
public class TabControl extends Manager {
public TabControl() {
super(0);
Background bitmapBackground = BackgroundFactory.createBitmapBackground(Bitmap.getBitmapResource("table_background.png"));
setBackground(bitmapBackground);
}
public int getPreferredWidth() {
return Display.getWidth();
}
public int getPreferredHeight() {
if (getFieldCount()>0)
return getField(0).getPreferredHeight();
else
return 5;
}
protected void sublayout(int width, int height) {
int x = 0;
int y = 0;
Field field;
int numberOfFields = getFieldCount();
for (int i=0; i<numberOfFields; ++i) {
field = getField(i);
setPositionChild(field, x, y);
layoutChild(field, width, height);
x += field.getPreferredWidth();
}
setExtent(getPreferredWidth(), getPreferredHeight());
}
protected boolean navigationMovement ( int dx, int dy, int status, int time ) {
int focusIndex = getFieldWithFocusIndex();
int columns = getFieldCount();
if (dx > 0 ) { //向右滚动
if ( focusIndex < columns-1 ) {
getField(focusIndex+1).setFocus();
return true;
}else {
getField(0).setFocus();
return true;
}
}
if (dx < 0) {//向左滚动
if ( focusIndex ==0 ) {
getField(columns-1).setFocus();
return true;
}else {
getField(focusIndex-1).setFocus();
return true;
}
}
//向上向下的滚动这里就不做处理了
return false;
}
}
--------------------------------------------------------------------------------------------------------
package cn.rim.samples.tabcontrol;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
public class TabItem extends BaseButtonField
{
private Bitmap[] _bitmaps;
private static final int NORMAL = 0;
private static final int FOCUS = 1;
private String text; //标签栏文字
/*
public BitmapButtonField( Bitmap normalState )
{
this( normalState, normalState, 0 );
}
*/
public TabItem( Bitmap normalState, Bitmap focusState )
{
this( normalState, focusState, 0 );
}
public TabItem( Bitmap normalState, Bitmap focusState, long style )
{
super( Field.FOCUSABLE | style );
if( (normalState.getWidth() != focusState.getWidth())
|| (normalState.getHeight() != focusState.getHeight()) ){
throw new IllegalArgumentException( "Image sizes don't match" );
}
_bitmaps = new Bitmap[] { normalState, focusState };
}
//Yang Jiang
public void setText(String value) {
this.text = value;
}
public void setImage( Bitmap normalState ){
_bitmaps[NORMAL] = normalState;
invalidate();
}
public void setFocusImage( Bitmap focusState ){
_bitmaps[FOCUS] = focusState;
invalidate();
}
public int getPreferredWidth() {
return _bitmaps[NORMAL].getWidth();
}
public int getPreferredHeight() {
return _bitmaps[NORMAL].getHeight();
}
protected void layout( int width, int height ) {
setExtent( _bitmaps[NORMAL].getWidth(), _bitmaps[NORMAL].getHeight() );
}
protected void paint( Graphics g ) {
int index = g.isDrawingStyleSet( Graphics.DRAWSTYLE_FOCUS ) ? FOCUS : NORMAL;
g.drawBitmap( 0, 0, _bitmaps[index].getWidth(), _bitmaps[index].getHeight(), _bitmaps[index], 0, 0 );
g.drawText(text, 0, this.getHeight()/2,
Graphics.VCENTER | Graphics.HCENTER, this.getWidth());
}
/**
* With this commented out the default focus will show through
* If an app doesn't want focus colours then it should override this and do nothing
**/
/*
protected void paintBackground( Graphics g ) {
// Nothing to do here
}
*/
protected void drawFocus( Graphics g, boolean on ) {
// Paint() handles it all
g.setDrawingStyle( Graphics.DRAWSTYLE_FOCUS, true );
paintBackground( g );
paint( g );
}
}
--------------------------------------------------------------------------------------------------------
package cn.rim.samples.tabcontrol;
import net.rim.device.api.system.*;
import net.rim.device.api.ui.*;
/**
* Implements all the stuff we don't want to do each time we need a new button
*/
public abstract class BaseButtonField extends Field
{
private XYRect _drawFocusTempRect = new XYRect();
public BaseButtonField()
{
this( 0 );
}
public BaseButtonField( long style )
{
super( Field.FOCUSABLE | style );
}
protected void layout( int width, int height )
{
setExtent( 10, 10 );
}
protected void drawFocus( Graphics g, boolean on )
{
getFocusRect( _drawFocusTempRect );
boolean oldDrawStyleFocus = g.isDrawingStyleSet( Graphics.DRAWSTYLE_FOCUS );
boolean notEmpty = g.pushContext( _drawFocusTempRect.x, _drawFocusTempRect.y, _drawFocusTempRect.width, _drawFocusTempRect.height, 0, 0 );
try {
if( notEmpty ) {
g.setDrawingStyle( Graphics.DRAWSTYLE_FOCUS, on );
paintBackground( g );
paint( g );
}
} finally {
g.popContext();
g.setDrawingStyle( Graphics.DRAWSTYLE_FOCUS, oldDrawStyleFocus );
}
}
protected boolean keyChar( char character, int status, int time )
{
if( character == Characters.ENTER ) {
clickButton();
return true;
}
return super.keyChar( character, status, time );
}
protected boolean navigationClick( int status, int time )
{
clickButton();
return true;
}
protected boolean trackwheelClick( int status, int time )
{
clickButton();
return true;
}
protected boolean invokeAction( int action )
{
switch( action ) {
case ACTION_INVOKE: {
clickButton();
return true;
}
}
return super.invokeAction( action );
}
public void setDirty( boolean dirty ) {
// We never want to be dirty or muddy
}
public void setMuddy( boolean muddy ) {
// We never want to be dirty or muddy
}
/**
* A public way to click this button
*/
public void clickButton()
{
fieldChangeNotify( 0 );
}
}
--------------------------------------------------------------------------------------------------------
package cn.rim.samples.tabcontrol;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.FocusChangeListener;
import net.rim.device.api.ui.Manager;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.component.LabelField;
import net.rim.device.api.ui.component.SeparatorField;
import net.rim.device.api.ui.container.HorizontalFieldManager;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.VerticalFieldManager;
import net.rim.device.api.ui.decor.Background;
import net.rim.device.api.ui.decor.BackgroundFactory;
public class DemoApp extends UiApplication {
public DemoApp() {
TabControlScreen screen = new TabControlScreen();
pushScreen(screen);
}
/**
* @param args
*/
public static void main(String[] args) {
DemoApp app = new DemoApp();
app.enterEventDispatcher();
}
private class TabControlScreen extends MainScreen implements FocusChangeListener {
private TabItem tab1;
private TabItem tab2;
private TabItem tab3;
private Manager tabArea;
private Manager tab1Manager;
private Manager tab2Manager;
private Manager tab3Manager;
public TabControlScreen() {
TabControl tabcontrol = new TabControl();
tab1 = new TabItem(Bitmap.getBitmapResource("tabitem_default.png"), Bitmap.getBitmapResource("tabitem_selected.png"));
tab1.setText("Page 1");
tab2 = new TabItem(Bitmap.getBitmapResource("tabitem_default.png"), Bitmap.getBitmapResource("tabitem_selected.png"));
tab2.setText("Page 2");
tab3 = new TabItem(Bitmap.getBitmapResource("tabitem_default.png"), Bitmap.getBitmapResource("tabitem_selected.png"));
tab3.setText("Page 3");
tab1.setFocusListener(this);
tab2.setFocusListener(this);
tab3.setFocusListener(this);
tabcontrol.add(tab1);
tabcontrol.add(tab2);
tabcontrol.add(tab3);
add(tabcontrol);
add(new SeparatorField());
tabArea = displayTab1();
add(tabArea);
}
public void focusChanged(Field field, int eventType) {
if (tabArea != null) {
if (eventType == FOCUS_GAINED) {
if (field == tab1) {
System.out.println("Switch to Tab 1");
delete(tabArea);
tabArea = displayTab1();
add(tabArea);
} else if (field == tab2) {
System.out.println("Switch to Tab 2");
System.out.println("Switch to Tab 1");
delete(tabArea);
tabArea = displayTab2();
add(tabArea);
} else if (field == tab3) {
System.out.println("Switch to Tab 3");
System.out.println("Switch to Tab 1");
delete(tabArea);
tabArea = displayTab3();
add(tabArea);
}
}
}
}
public Manager displayTab1() {
if (tab1Manager == null) {
tab1Manager = new VerticalFieldManager();
tab1Manager.add(new LabelField ("Tab 1 content here."));
tab1Manager.add(new LabelField ("Tab 1 content here again."));
}
return tab1Manager;
}
public Manager displayTab2() {
if (tab2Manager == null) {
tab2Manager = new VerticalFieldManager();
tab2Manager.add(new LabelField ("Tab 2 content here."));
tab2Manager.add(new LabelField ("Tab 2 content here again."));
}
return tab2Manager;
}
public Manager displayTab3() {
if (tab3Manager == null) {
tab3Manager = new VerticalFieldManager();
tab3Manager.add(new LabelField ("Tab 3 content here."));
tab3Manager.add(new LabelField ("Tab 3 content here again."));
}
return tab3Manager;
}
}
}
--------------------------------------------------------------------------------------------------------