blackberry 5.0 api image mask/background image position - blackberry

I've just started learning to develop blackberry apps and I've hit a bit of a snag. I'm unsure how I could move around a background image that is large than the field/manager it is being applied to. Here's an image to illustrate what I mean:
So far I have tried adding a Bitmap to a BitmapField inside a AbsolutePositionManager thinking I would be able to set the size of the absolute manager and just move the bitmapfield around inside it. That isn't the case, the manage just takes the size of the content inside it :(
I come from a frontend web dev background so what I'm looking for is something that behaves similar to the 'background-position' attribute in css or some sort of image mask.
Thanks in advance!
-- update --
This is a code sample of where I have got to. I now have a custom sized manager that displays a chunk of a larger BitmapField. I just need a way to move that BitmapField around.
package mypackage;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.ui.component.BitmapField;
import net.rim.device.api.ui.container.AbsoluteFieldManager;
public class MyImage extends AbsoluteFieldManager {
protected void sublayout(int maxWidth, int maxHeight){
int displayWidth = 326;
int displayHeight = 79;
super.sublayout(displayWidth, displayHeight);
setExtent(displayWidth, displayHeight);
}
public MyImage(){
Bitmap _image = Bitmap.getBitmapResource("img.jpg");
BitmapField image = new BitmapField(_image);
add(image);
}
}

Rather than adding it as a Field, just store a reference to it somewhere in your Manager and then paint it yourself. Here's an untested example:
public class MyManager extends VerticalFieldManager() {
Bitmap _bg;
public MyManager() {
_bg = Bitmap.getBitmapResource("img.jpg");
}
protected void paint(Graphics graphics) {
graphics.drawBitmap(x_offset, y_offset, _bg.getWidth(), _bg.getHeight(), _bg, 0, 0);
super.paint(graphics);
}
}
Now you can just set x_offset and y_offset to whatever you want and it'll be shifted. If you need to mess with the size of the Manager to fit the Bitmap, add:
protected void sublayout(int width, int height) {
super.sublayout(width, height);
setExtent(Math.min(width, Math.max(getWidth(), _bg.getWidth())), Math.min(height, Math.max(getHeight(), _bg.getHeight()));
}
Hope this helps!

Related

Blackberry Animation Issue on App's Home Screen

I am trying to create an Application which has a Home Screen (MyScreen below) animation in Blackberry which makes an image float from the bottom to middle of the screen. Then after that, i want to push another Screen which brings a Login Screen or something (NewScreen below).
I am getting a blank Screen after the animation. On pressing back once, i am getting the Screen i pushed from the Animation Screen. Please guide me: where should i push to get the perfect result?
import net.rim.device.api.animation.AnimatedScalar;
import net.rim.device.api.animation.Animation;
import net.rim.device.api.animation.Animator;
import net.rim.device.api.animation.AnimatorListener;
import net.rim.device.api.system.Bitmap;
import net.rim.device.api.system.Display;
import net.rim.device.api.system.EncodedImage;
import net.rim.device.api.ui.Color;
import net.rim.device.api.ui.Graphics;
import net.rim.device.api.ui.Screen;
import net.rim.device.api.ui.TransitionContext;
import net.rim.device.api.ui.Ui;
import net.rim.device.api.ui.UiApplication;
import net.rim.device.api.ui.UiEngineInstance;
import net.rim.device.api.ui.container.MainScreen;
import net.rim.device.api.ui.container.PopupScreen;
/**
* A class extending the MainScreen class, which provides default standard
* behavior for BlackBerry GUI applications.
*/
public final class MyScreen extends MainScreen implements AnimatorListener {
private RectangleToMove _rect;
private Animator _animator;
private Animation _xanimation;
private Animation _yanimation;
private boolean _bAnimating;
public static final int BALL_WIDTH = 50;
public Bitmap splashimg;
static TransitionContext transitionContextIn;
static TransitionContext transitionContextOut;
static UiEngineInstance engine = Ui.getUiEngineInstance();
/**
* Creates a new MyScreen object
*/
public MyScreen() {
EncodedImage img = EncodedImage.getEncodedImageResource("logo.png");
splashimg = img.getBitmap();
_bAnimating = false;
int midScreen = (Display.getWidth() / 2) - img.getWidth()/2;
int endScreen = Display.getHeight();
_rect = new RectangleToMove(midScreen, BALL_WIDTH);
_animator = new Animator(30);
_animator.setAnimatorListener(this);
_yanimation = _animator.addAnimationFromTo(_rect.getY(),
AnimatedScalar.ANIMATION_PROPERTY_SCALAR, endScreen
- BALL_WIDTH, Display.getHeight() / 2-30,
Animation.EASINGCURVE_LINEAR, 3000L);
_yanimation.setRepeatCount(1f);
_yanimation.begin(0);
UiApplication.getUiApplication().pushScreen(new NewScreen());
}
protected void paint(Graphics g) {
if (_bAnimating) {
_rect.draw(g, splashimg);
}
}
public void animatorUpdate() {
invalidate();
doPaint();
}
public void animatorProcessing(boolean processing) {
_bAnimating = processing;
}
}
class RectangleToMove {
private int xPos;
private AnimatedScalar yPos;
public void draw(Graphics g, Bitmap splashimg) {
g.setBackgroundColor(Color.BLACK);
g.clear();
g.setColor(Color.SLATEGRAY);
g.drawBitmap(xPos, yPos.getInt(), splashimg.getWidth(),
splashimg.getHeight(), splashimg, 0, 0);
/*
* g.fillEllipse(xPos,yPos.getInt(),
* xPos+MyScreen.BALL_WIDTH,yPos.getInt(),xPos,
* yPos.getInt()+MyScreen.BALL_WIDTH,0,360);
*/
}
public int getX() {
return xPos;
}
public AnimatedScalar getY() {
return yPos;
}
RectangleToMove(int x, int y) {
xPos = x;
yPos = new AnimatedScalar(y);
}
}
I'm not 100% sure I understand your problem, but I edited your question to describe what I think is the problem.
When your animation ends, you're seeing a blank white screen that you don't want. You have to press Back/ESC to make the white screen disappear, so that you can get back to your login screen (NewScreen). I assume you don't want to see the initial animation screen after it first shows (probably because it's a loading, or splash screen).
In order to do this, you need to wait until the animation completes before pushing your second screen. So, remove this call to pushScreen:
UiApplication.getUiApplication().pushScreen(new NewScreen());
that you have in the MyScreen constructor. At that point, the animation has not completed, so it's too soon to push the NewScreen.
Then, push the screen when the AnimatorListener is told that the animation has stopped. If you don't want the animation screen to be visible, when backing through your screens, then pop it after pushing the second screen:
public void animatorProcessing(boolean processing) {
_bAnimating = processing;
if (!processing) {
// the animation is complete
UiApplication.getUiApplication().pushScreen(new NewScreen());
// use this line if the instance of `MyScreen` should not be
// visible after the user presses Back/ESC:
UiApplication.getUiApplication().popScreen(this);
}
}

Multiple column list field

I am facing issue while displaying multiple columns in a row. I need multiple columns and multiple row list field. Now I am trying to make this using label field i one of my case its working quite good but in another case I am facing an issue please help me out. My code is:
VerticalFieldManager TOrderVFM = new VerticalFieldManager()
for ( int i = 0; i <10; i++)
{
HorizontalFieldManager temphfm1 = new HorizontalFieldManager(){
protected void sublayout(int width, int height)
{
int w = 480;
int h = 400;
super.sublayout(w, h);
super.setExtent(w, h);
}
};
TOrderVFM.add(temphfm1);
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("orderDate").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("id").toString()));
temphfm1.add(.createDayName1(MTradeOrderSoap.objects[i].getProperty("label").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("quantityPending").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("securityName").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("priceType").toString()));
temphfm1.add(createDayName1(MTradeOrderSoap.objects[i].getProperty("orderOrigin").toString()));
temphfm1.add(ut.createDayName1(MTradeOrderSoap.objects[i].getProperty("orderStatus").toString()));
}
This loop is inserting values that are coming from the soap response and passing it to the method named createDayName() which is also given below.Now this all works good for my one of the screens but when i try to follow this for my another screen i am facing an error:-WARNING: Cannot layout field, insufficient height or width
I have set the width and height of both the managers but nothing seems to be working .Please provide me a support to do that.
public LabelField createDayName1(final String day)
{
LabelField cell = new LabelField("", Field.NON_FOCUSABLE) {
protected void layout(int width, int height)
{
int w = Display.getWidth()/7;
int h = 40;
super.layout(w, h);
super.setExtent(w, h);
}
protected void paint(Graphics g)
{
g.setColor(0xFF9912);
g.setFont(dayNameFont);
g.fillRect(0, 0, getWidth(), getHeight());
g.setColor(Color.BLACK);
// g.setColor(0x466385);
g.drawText(day.trim(), getWidth() / 2 - dayNameFont.getAdvance(day) / 3, getHeight() / 3 - dayNameFont.getHeight() / 2);
super.paint(g);
}
};
return cell;
}
In layout() and sublayout() you need to make sure you're comparing the width and height you are passing to setExtent() (and super.layout()/super.sublayout() for that matter) to the arguments getting sent to those methods because they are the maximum available width and height. If you try to tell the Field to be wider or taller (using setExtent()) than what is available, it won't be able to display properly.

Background image behind two fields in custom HorizontalFieldManager

Below code defines a horizontal field manager with two fields. How can I amend the code so that the background is just set on the two fields being added not on the whole manager. Note, im not attempting to add an individual background image to each of the fields, instead a shared background image that spans behind the two fields.
LabelField label = new LabelField("name");
TextField e = new TextField(Field.FOCUSABLE);
final Bitmap b = Constants.SETTINGS;
final Background bg = BackgroundFactory.createBitmapBackground(Constants.SETTINGS);
HorizontalFieldManager manager = new HorizontalFieldManager()
{
public void sublayout (int width, int height)
{
Field field;
int x = 0;
super.sublayout(b.getWidth(), height);
super.setExtent(b.getWidth(), height);
for (int i = 0; i < getFieldCount(); i++)
{
field = getField(i);
layoutChild(field, Display.getWidth()/2, height);
setPositionChild(field, x, 10);
x += Display.getWidth()/2;
}
}
};
manager.add (label);
manager.add (e);
add (manager);
Rather than putting them in a custom Manager, it may be easier to just override the Fields' layout() calls to be
protected void layout(int width, int height) {
super.layout(width, height);
setExtent(Display.getWidth()/2, this.getHeight());
}
and then you can just use a normal HorizontalFieldManager you can set a background on and a padding (hfm.setPadding(10, 10, 10, 10);). Adding a padding will reduce the available width for your Fields, so you should decrease their widths in the layout() calls.
You can offset each of their individual backgrounds with some fancy, expensive Bitmap footwork (math) to appear to "share" one image using setBackGround(), or you can override their draw methods to achieve the same effect with the ability to "move" across the bitmap according to their relative position...
That what you're after? :)
edit:
create a custom field to use your bitmap and feed it whatever content you would like, then override the paint to draw what you like where you like it...
protected void paint(Graphics g){
// conditionals, etc
g.drawBitmap(x, y, width, height, bitmap, left, top);
// color changes, etc
g.drawText(yourText);
// clean up
}

What is the easiest way to set background image of the application on Blackberry

I know, this question was asked before. However I can't beleive that this operation is so difficult. I think i miss some important points on developing Blackberry applications.
Try to use the following code:
Bitmap backgroundBitmap = Bitmap.getBitmapResource("background.png");
HorizontalFieldManager horizontalFieldManager = new
HorizontalFieldManager(HorizontalFieldManager.USE_ALL_WIDTH |
HorizontalFieldManager.USE_ALL_HEIGHT){
//Override the paint method to draw the background image.
public void paint(Graphics graphics)
{
//Draw the background image and then call super.paint
//to paint the rest of the screen.
graphics.drawBitmap(0, 0, Display.getWidth(), Display.getHeight(),
backgroundBitmap, 0, 0);
super.paint(graphics);
}
};

Adding fields until screen is full

For the sake of this question, let us suppose that I want a row of buttons. I want to put as many buttons in that row as I can fit on the screen, but no more. In other words, as long as a prospective button will not be cut off or have its text shortened, add it.
It seems that I should be able to do something like:
HorizontalFieldManager hfm = new HorizontalFieldManager();
int remainingWidth = Display.getWidth();
int i =0;
while(true) {
ButtonField bf = new ButtonField("B " + i);
remainingWidth -= bf.getWidth();
if(remainingWidth<0)
break;
hfm.add(bf);
i++;
}
add(hfm);
But this doesn't work. bf.getWidth() is always 0. I suspect that this is because the button has not yet been laid out when I query for the width.
So, perhaps I could just make sure the buttons are always the same size. But this won't work for a few reasons:
Different BB platforms have different looks for buttons and text that will fit on a button on a Curve won't fit on a button on a Storm.
3rd party themes may change the look of buttons, so I can't even count on buttons being a certain size on a certain platform.
Is there no way for me to actually check the remaining space before adding a button? It feels like a fairly useful feature; am I just missing something?
Try to draw the Manager before adding component to it.
You should probably add the padding too, if the button has one.
public class Main extends UiApplication{
public static void main(String[] args) {
Main main = new Main();
main.enterEventDispatcher();
}
public Main() {
Screen main = new Screen();
this.pushScreen(main);
main.init();
}
}
public class Screen extends MainScreen {
HorizontalFieldManager hfm;
public Screen() {
hfm = new HorizontalFieldManager();
this.add(hfm);
}
public void init() {
int remainingWidth = Display.getWidth();
int i = 0;
while(true) {
ButtonField bf = new ButtonField("B " + i);
hfm.add(bf);
remainingWidth -= bf.getWidth();
System.out.println(remainingWidth);
if(remainingWidth <= 0) {
hfm.delete(bf);
break;
}
i++;
}
}
You're correct that getWidth() returns the width of the field after it's been laid out (that's why it's 0), but getPreferredWidth() will return the value that's given to the Layout Manager, and is probably what you want.
The other problem you have is that you're comparing remainingWidth to 0. If a button's preferred width is, say, 36 pixels, and the remaining width is 20 pixels, you'll draw a button in a spot where you don't have enough room to display it.
Try something like this:
HorizontalFieldManager hfm = new HorizontalFieldManager();
int remainingWidth = Display.getWidth();
for (int i; true; i++ ) {
ButtonField bf = new ButtonField("B " + i);
int preferredWidth = bf.getPreferredWidth();
if ( remainingWidth < preferredWidth )
break;
remainingWidth -= preferredWidth;
hfm.add(bf);
}
add(hfm);
Try to make your own HorizontalFiledManager (extends Manager) and override
protected void sublayout( int maxWidth, int maxHeight ){
setExtent(maxWidth,maxHeight);
}
Get the number of childs, and with a for loop go trough and start to lay out the childs (setPosition, layoutChild).
When you lay out the child, count his width and always check if the counted width + the next child`s width is greater then maxWidth then do not lay out and break the for loop.
Hopefully this help you.

Resources