I am calling invalidate() which is calling onDraw(). The bitmap that I wish to show on the screen is not being displayed after running doInBackGround(). Can anyone help?
Here is what I have tested out so far.
When I place the same line of code
canvas.drawBitmap();
in onPreExecute() it works, but in onPostExecute() it does not display the expected results.
This is my code:
public class FloorAppActivity extends Activity {
private Context globalContext;
private Point displaySize;
private int displayWidth;
private int displayHeight;
private String floorID;
private String floorName;
private String floorGridNumStr;
private int floorGridNum;
private String floorNumStr;
private int positionX;
private int positionY;
private int XCoord;
private int YCoord;
private int ZCoord;
private float signalStr;
private Integer dBm;
private Bitmap floorPlan;
private Bitmap userMark;
private Bitmap redPin;
private FloorView floorView;
private Connection conn = null;
private Canvas canvas=null;
private int newScrollRectX=0;
private int newScrollRectY=0;
private Paint paint;
private boolean a = false;
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
globalContext = this;
floorID = getIntent().getStringExtra("floorID");
floorName = getIntent().getStringExtra("floorName");
positionX = getIntent().getIntExtra("userPositionX",-1);
positionY = getIntent().getIntExtra("userPositionY",-1);
dBm = getIntent().getIntExtra("BestSignal", -1);
//Get the grid number
if(Integer.parseInt(floorName.substring(floorName.lastIndexOf("_")+1))<10)
floorGridNumStr = floorName.substring(8, 9);
else
floorGridNumStr = floorName.substring(8, 10);
floorGridNum = Integer.parseInt(floorGridNumStr);
floorNumStr = floorName.substring(5,7);
Display display = ((WindowManager) getSystemService(Context.WINDOW_SERVICE)).getDefaultDisplay();
displaySize = new Point();
try {
// GetSize is not available in older models of Android
display.getSize(displaySize);
} catch (java.lang.NoSuchMethodError ignore) { // Older device
displaySize.x = display.getWidth();
displaySize.y = display.getHeight();
}
try {
InputStream source = getAssets().open(floorID);
floorPlan = BitmapFactory.decodeStream(source);
displayWidth = Math.min(displaySize.x, floorPlan.getWidth());
displayHeight = Math.min(displaySize.y, floorPlan.getHeight());
userMark = BitmapFactory.decodeResource(getResources(),R.drawable.star);
redPin = BitmapFactory.decodeResource(getResources(),R.drawable.redpin);
floorView = new FloorView(this);
setContentView(floorView);
}
catch (IOException e) {
MapServerAPI server = new MapServerAPI(globalContext,"Retrieving floor plan. Please wait...") {
#Override
protected void onPostExecute(Bitmap bitmap) {
super.onPostExecute(bitmap);
if (bitmap == null)
Toast.makeText(globalContext, "Error in retrieving floor plan!", Toast.LENGTH_LONG).show();
else {
floorPlan = bitmap;
displayWidth = Math.min(displaySize.x, floorPlan.getWidth());
displayHeight = Math.min(displaySize.x, floorPlan.getHeight());
userMark = BitmapFactory.decodeResource(getResources(),R.drawable.star);
redPin = BitmapFactory.decodeResource(getResources(),R.drawable.redpin);
floorView = new FloorView(globalContext);
setContentView(floorView);
}
}
};
server.execute(floorID);
}
}
#Override
public void onResume() {
super.onResume();
registerReceiver(broadcastReceiver,new IntentFilter("FingerPrint_LOCATION_UPDATE"));
}
#Override
public void onPause() {
super.onPause();
unregisterReceiver(broadcastReceiver);
}
// listen for user location change
private BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
#Override
public void onReceive(Context context, Intent intent) {
String result = intent.getStringExtra("location");
Toast.makeText(context,result,Toast.LENGTH_LONG).show();
String floorId = intent.getStringExtra("floorID");
floorName = intent.getStringExtra("name");
dBm = intent.getIntExtra("BestSignal", -1);
int userLocationX = intent.getIntExtra("userPositionX",-1);
int userLocationY = intent.getIntExtra("userPositionY",-1);
//Get the grid number
if(Integer.parseInt(floorName.substring(floorName.lastIndexOf("_")+1))<10)
floorGridNumStr = floorName.substring(8, 9);
else
floorGridNumStr = floorName.substring(8, 10);
floorGridNum = Integer.parseInt(floorGridNumStr);
floorNumStr = floorName.substring(5,7);
if(!floorId.equals(floorID)){
positionX = userLocationX;
positionY = userLocationY;
InputStream source=null;
try {
source = getAssets().open(floorID);
} catch (IOException e) {
}
floorPlan = BitmapFactory.decodeStream(source);
floorView.postInvalidate();
}
}
};
private class FloorView extends View {
private Rect displayRect; //rect we display to
private Rect scrollRect; //rect we scroll over our bitmap with
private int scrollRectX = 0; //current left location of scroll rect
private int scrollRectY = 0; //current top location of scroll rect
private float scrollByX = 0; //x amount to scroll by
private float scrollByY = 0; //y amount to scroll by
private float startX = 0; //track x from one ACTION_MOVE to the next
private float startY = 0; //track y from one ACTION_MOVE to the next
public FloorView(Context context) {
super(context);
// Destination rect for our main canvas draw. It never changes.
displayRect = new Rect(0, 0, displayWidth, displayHeight);
// Scroll rect: this will be used to 'scroll around' over the
// bitmap in memory.
if (positionX + displayWidth / 2 > floorPlan.getWidth())
scrollRectX = floorPlan.getWidth() - displayWidth;
else
scrollRectX = positionX - displayWidth / 2;
if (scrollRectX < 0)
scrollRectX = 0;
if (positionY + displayHeight / 2 > floorPlan.getHeight())
scrollRectY = floorPlan.getHeight() - displayHeight;
else
scrollRectY = positionY - displayHeight / 2;
if (scrollRectY < 0)
scrollRectY = 0;
scrollRect = new Rect(scrollRectX, scrollRectY, displayWidth, displayHeight);
}
#Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
// Remember our initial down event location.
startX = event.getRawX();
startY = event.getRawY();
break;
case MotionEvent.ACTION_MOVE:
float x = event.getRawX();
float y = event.getRawY();
// Calculate move update. This will happen many times
// during the course of a single movement gesture.
scrollByX = x - startX; //move update x increment
scrollByY = y - startY; //move update y increment
startX = x; //reset initial values to latest
startY = y;
invalidate(); //force a redraw
break;
}
return true; //done with this event so consume it
}
#Override
protected void onDraw(Canvas canvas1) {
canvas=canvas1;
// Our move updates are calculated in ACTION_MOVE in the opposite direction
// from how we want to move the scroll rect. Think of this as dragging to
// the left being the same as sliding the scroll rect to the right.
newScrollRectX = scrollRectX - (int)scrollByX;
newScrollRectY = scrollRectY - (int)scrollByY;
// Don't scroll off the left or right edges of the bitmap.
if (newScrollRectX < 0)
newScrollRectX = 0;
else if (newScrollRectX > (floorPlan.getWidth() - displayWidth))
newScrollRectX = (floorPlan.getWidth() - displayWidth);
// Don't scroll off the top or bottom edges of the bitmap.
if (newScrollRectY < 0)
newScrollRectY = 0;
else if (newScrollRectY > (floorPlan.getHeight() - displayHeight))
newScrollRectY = (floorPlan.getHeight() - displayHeight);
// We have our updated scroll rect coordinates, set them and draw.
scrollRect.set(newScrollRectX, newScrollRectY,
newScrollRectX + displayWidth, newScrollRectY + displayHeight);
paint = new Paint();
canvas.drawBitmap(floorPlan, scrollRect, displayRect, paint);
// Update user position
if (positionX >= newScrollRectX && positionX - newScrollRectX <= displayWidth
&& positionY >= newScrollRectY && positionY - newScrollRectY <= displayHeight)
canvas.drawBitmap(userMark,positionX-newScrollRectX-userMark.getWidth()/2,positionY-newScrollRectY-userMark.getHeight()/2,paint);
class AsyncTaskToConnect extends AsyncTask <Void, Void, Void>{
#Override
protected Void doInBackground(Void... cmd) {
// connect to database and retrieve values
return null;
}
#Override
protected void onPostExecute(Void v)
{//PE
if (positionX >= newScrollRectX && positionX - newScrollRectX <= displayWidth
&& positionY >= newScrollRectY && positionY - newScrollRectY <= displayHeight)
{
canvas.drawBitmap(redPin,480-newScrollRectX-userMark.getWidth()/2,90-newScrollRectY-userMark.getHeight()/2,paint);
}
//return null;
// Reset current scroll coordinates to reflect the latest updates,
// so we can repeat this update process.
scrollRectX = newScrollRectX;
scrollRectY = newScrollRectY;
}//PE
}
AsyncTaskToConnect[] asyncTaskC = null;
asyncTaskC = new AsyncTaskToConnect[1];
asyncTaskC[0] = new AsyncTaskToConnect();
asyncTaskC[0].executeOnExecutor(AsyncTask.THREAD_POOL_EXECUTOR);
}
#Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
// Cache our new dimensions; we'll need them for drawing.
displayWidth = Math.min(w, floorPlan.getWidth());
displayHeight = Math.min(h, floorPlan.getHeight());
// Destination rect for our main canvas draw.
displayRect = new Rect(0, 0, displayWidth, displayHeight);
// Scroll rect: this will be used to 'scroll around' over the
// bitmap in memory.
if (positionX + displayWidth / 2 > floorPlan.getWidth())
scrollRectX = floorPlan.getWidth() - displayWidth;
else
scrollRectX = positionX - displayWidth / 2;
if (scrollRectX < 0)
scrollRectX = 0;
if (positionY + displayHeight / 2 > floorPlan.getHeight())
scrollRectY = floorPlan.getHeight() - displayHeight;
else
scrollRectY = positionY - displayHeight / 2;
if (scrollRectY < 0)
scrollRectY = 0;
scrollRect = new Rect(scrollRectX, scrollRectY, displayWidth, displayHeight);
super.onSizeChanged(w, h, oldw, oldh);
}
}
}
P.S. This is my first time posting. Please pardon me if i make mistakes in my post. Thanks.
I think the problem is that you are storing the Canvas object passed into the onDraw method. The object may not be valid after the onDraw method has returned.
It looks like you are trying to prepare a Bitmap on a background thread and then draw it on screen when it has been prepared. The way you do it is - prepare the Bitmap and just call invalidate on the View in onPostExecute method. Then in the onDraw method, you can take that Bitmap object and draw it using canvas.drawBitmap
Related
I want to create a camera movement like idle miner tycoon. So the Camera should scroll vertically by panning with a typically scroll effect.
This is my code:
Vector3 touchStart;
public int upperLimit = 0;
public int lowerLimit = 7000;
void Update()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = Camera.main.ScreenToWorldPoint(Input.mousePosition);
}
if (Input.GetMouseButton(0))
{
Vector3 direction = touchStart - Camera.main.ScreenToWorldPoint(Input.mousePosition);
float finalYPos = Camera.main.transform.position.y + direction.y;
finalYPos = Mathf.Clamp(finalYPos, lowerLimit, upperLimit);
Camera.main.transform.position = new Vector3(Camera.main.transform.position.x, finalYPos, Camera.main.transform.position.z);
Debug.Log(finalYPos);
}
}
But how can I make that the scrolling is ran out. Actually the movement is stopping directly when I leave the mouse/thump.
Thank you for your help
Best regards
I found a Solution for everybody with the same problem:
[SerializeField]
private Camera cam;
Vector3 touchStart;
private float topLimit = 0f;
private float bottomLimit = -2000.0f;
private Vector3 _curPosition;
private Vector3 _velocity;
private bool _underInertia;
private float _time = 0.0f;
public float SmoothTime = 2;
public Vector3 direction;
void Update()
{
PanCamera();
if (_underInertia && _time <= SmoothTime)
{
cam.transform.position += _velocity;
float newY = Mathf.Clamp(cam.transform.position.y, bottomLimit, topLimit);
cam.transform.position = new Vector3(cam.transform.position.x, newY, cam.transform.position.z);
_velocity = Vector3.Lerp(_velocity, Vector3.zero, _time);
_time += Time.smoothDeltaTime;
}
else
{
_underInertia = false;
_time = 0.0f;
}
}
private void PanCamera()
{
if (Input.GetMouseButtonDown(0))
{
touchStart = cam.ScreenToWorldPoint(Input.mousePosition);
_underInertia = false;
}
if (Input.GetMouseButton(0))
{
Vector3 _prevPosition = _curPosition;
direction = touchStart - cam.ScreenToWorldPoint(Input.mousePosition);
float finalYPos = cam.transform.position.y + direction.y;
Debug.Log("Old: " + finalYPos);
finalYPos = Mathf.Clamp(finalYPos, bottomLimit, topLimit);
Debug.Log("New: " + finalYPos);
Vector3 desiredPosition = new Vector3(cam.transform.position.x, finalYPos, cam.transform.position.z);
cam.transform.position = desiredPosition;
_curPosition = desiredPosition;
_velocity = _curPosition - _prevPosition;
}
if (Input.GetMouseButtonUp(0))
{
_underInertia = true;
}
}
I am trying to use code gathered off of this website to make an application that bounces circles around. when i click now - it creates a circle that just seems to vibrate in place and does not bounce off of the borders.
HERE IS THE CODE HAT SOLLVED MY ISSUE THANKS GUYS
#FXML
private AnchorPane anchorPane;
#FXML
private Label ballCountLabel;
public int ballCount = 0;
public int mouseClick = 0;
Circle[] balls = new Circle[1000];
#Override
public void initialize(URL url, ResourceBundle rb) {
pane.setBackground(new Background(new BackgroundFill(Color.WHITE, CornerRadii.EMPTY, Insets.EMPTY)));
AnchorPane.setTopAnchor(pane, 0.0);
AnchorPane.setLeftAnchor(pane, 0.0);
AnchorPane.setTopAnchor(pane, 0.0);
AnchorPane.setRightAnchor(pane, 0.0);
}
#FXML
private void mouseAddBall(MouseEvent event) throws Exception {
balls[mouseClick] = new Circle(15, Color.BLANCHEDALMOND);
balls[mouseClick].relocate(event.getSceneX(), event.getSceneY());
pane.getChildren().add(balls[mouseClick]);
ballCount++;
ballCountLabel.setText("Ball Count: " + ballCount);
addBallMovement(balls[mouseClick]);
mouseClick++;
}
public void addBallMovement(Circle b){
final Timeline loop = new Timeline(new KeyFrame(Duration.millis(10), new EventHandler<ActionEvent>() {
double deltaX = 3;
double deltaY = 3;
#Override
public void handle(ActionEvent t) {
b.setLayoutX(b.getLayoutX() + deltaX);
b.setLayoutY(b.getLayoutY() + deltaY);
final Bounds bounds = pane.getBoundsInParent();
final boolean atRightBorder = b.getLayoutX() >= (bounds.getMaxX() - b.getRadius());
final boolean atLeftBorder = b.getLayoutX() <= (bounds.getMinX() + b.getRadius());
final boolean atBottomBorder = b.getLayoutY() >= (bounds.getMaxY() - b.getRadius());
final boolean atTopBorder = b.getLayoutY() <= (bounds.getMinY() + b.getRadius());
if (atRightBorder || atLeftBorder) {
deltaX *= -1;
}
if (atBottomBorder || atTopBorder) {
deltaY *= -1;
}
}
}));
loop.setCycleCount(Timeline.INDEFINITE);
loop.play();
I changed Ball to Circle to test your code. You are changing to the next ball in the balls array before you add movement to the current ball. This is probably giving you a NullPointerException.
Change
balls[mouseClick] = new Circle(event.getSceneX(), event.getSceneY(),
Math.random() * 20);
pane.getChildren().add(balls[mouseClick]);
mouseClick++;
ballCount++;
ballCountLabel.setText("Ball Count: " + ballCount);
addBallMovement(balls[mouseClick]); //<--You want to move the current ball. This code needs to be before mouseClick++
To:
balls[mouseClick] = new Circle(event.getSceneX(), event.getSceneY(),
Math.random() * 20);
pane.getChildren().add(balls[mouseClick]);
addBallMovement(balls[mouseClick]);
mouseClick++;
ballCount++;
ballCountLabel.setText("Ball Count: " + ballCount);
I have a game like WorldSearch on Store, I tried using this solution:
I created matrix by array of TextView and added TouchEvent on each TextView. Then I caught event by MOTION.UP, MOTION.DOWN. When I touched on a TextView and dragged it, although it went thought other TextViews but I just could get event of first TextView.
Here is code:
private void createMetrix(){
// amound of item in a row and column
int itemNum = 10;
// calculate size of item
ScreenDimension screenDimension = Utilities.getFinalScreenDimension(this);
int itemSize = screenDimension.screenWidth / 10;
// mContentLinear has VERTICAL orientation
// then adding children linear layouts, these layout has HORIZONTAL orientation
for(int i = 0; i < itemNum; i++) {
LinearLayout theItemLayout = createHorizontalLayout(itemNum, itemSize, i);
mContentLinear.addView(theItemLayout);
}
}
private LinearLayout createHorizontalLayout(int itemNum, int itemSize, int row) {
LinearLayout theLinear = new LinearLayout(this);
theLinear.setOrientation(LinearLayout.HORIZONTAL);
theLinear.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, itemSize));
for(int i = 0; i < itemNum; i++){
// add item metrix into linear layout having HORIZONTAL orientation
TextView itemTxt = createItemMatrix(itemSize, row, i);
theLinear.addView(itemTxt);
}
return theLinear;
}
private TextView createItemMatrix(int itemSize, int row, int column) {
TextView theItemTxt = new TextView(this);
theItemTxt.setWidth(itemSize);
theItemTxt.setHeight(itemSize);
theItemTxt.setTextSize(13);
theItemTxt.setGravity(Gravity.CENTER);
theItemTxt.setText("A" + row + "" + column);
String tag = row + "|" + column;
theItemTxt.setTag(tag);
theItemTxt.setOnTouchListener(mOnTouchListener);
return theItemTxt;
}
// Listener
private View.OnTouchListener mOnTouchListener = new View.OnTouchListener() {
private Rect rect;
#Override
public boolean onTouch(View v, MotionEvent event) {
if (v == null) return true;
TextView itemTxt = (TextView)v;
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
rect = new Rect(v.getLeft(), v.getTop(), v.getRight(), v.getBottom());
Log.d("TEXT", "MOVE DOWN: " + itemTxt.getText().toString());
return true;
case MotionEvent.ACTION_UP:
if (rect != null
&& !rect.contains(v.getLeft() + (int) event.getX(),
v.getTop() + (int) event.getY())) {
// The motion event was outside of the view, handle this as a non-click event
return true;
}
// The view was clicked.
Log.d("TEXT", "MOVE ON: " + itemTxt.getText().toString());
// TODO: do stuff
return true;
case MotionEvent.ACTION_MOVE:
Log.d("TEXT", "MOVE OUT: " + itemTxt.getText().toString());
return true;
default:
return true;
}
}
};
Does someone have any ideas on this case?
Thanks,
Ryan
I continuously have this problem with all my most recent animation projects. Every time I run my animations, they never seem to be completely visible and full, but rather they blink and flash similar to a light bulb that is not fully screwed in ( i know, strange comparison but I can't think of what else it resembles). I feel like it must have something to do with my placement of repaint(); but I'm just not sure at this point. On a previous animation I made, the problem was that my "private BufferedImage offScr" variable wasn't set correctly, but viewing other programs similar to the one I am working on now, I don't see why that variable would be necessary. Thanks for all your help folks, and I apologize for my lack of knowledge in programming vocabulary.
Here is my program so far:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.awt.image.BufferedImage;
public class DoveAnimator extends JFrame implements ActionListener {
private int DELAY = 40; // the delay for the animation
private final int WIDTH = 400; // the window width
private final int HEIGHT = 180; // the window height
private final int IMAGEAMT = 8;
private Image [] doveLeft = new Image[IMAGEAMT];
private Image [] doveRight = new Image[IMAGEAMT];
private int doveIndex = 0;
private boolean isRight = true;
private JPanel dovePanel;
private Image dove;
private JButton slowerButton = new JButton ("Slower");
private JButton fasterButton = new JButton ("Faster");
private JButton reverseButton = new JButton ("Reverse");
private JButton pauseResumeButton = new JButton (" pause ");
private Timer timer;
private int clicks = 2;
private boolean pause = false;
/** The constructor */
public DoveAnimator() {
MediaTracker track = new MediaTracker(this);
for (int i = 0; i < IMAGEAMT; ++i) {
doveLeft[i] = new ImageIcon("doves/ldove" + (i+1) + ".gif").getImage();
doveRight[i] = new ImageIcon("doves/rdove" + (i+1) + ".gif").getImage();
track.addImage(doveLeft[i],0);
track.addImage(doveRight[i],0);
}
// dove = doveRight[0];
//track.addImage(bkgImage,0);
// track.addImage(dove,0);
try {
track.waitForAll();
} catch ( InterruptedException e ) { }
dove = doveRight[0];
JPanel mainPanel = new JPanel();
mainPanel.setPreferredSize(new Dimension(WIDTH, HEIGHT));
setTitle ("Dove Animator");
dovePanel = new JPanel();
dovePanel.setPreferredSize(new Dimension(100, 125));
dovePanel.setBackground(Color.WHITE);
mainPanel.add(dovePanel);
JPanel buttonPanel = new JPanel();
buttonPanel.setPreferredSize(new Dimension(WIDTH, 40));
// button 1
slowerButton.addActionListener (this);
buttonPanel.add (slowerButton);
// button 2
fasterButton.addActionListener (this);
buttonPanel.add (fasterButton);
// button 3
reverseButton.addActionListener (this);
buttonPanel.add (reverseButton);
// button 4
pauseResumeButton.addActionListener (this);
buttonPanel.add (pauseResumeButton);
mainPanel.add(buttonPanel);
add(mainPanel);
setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
setVisible (true);
pack();
timer = new Timer(DELAY,this); // setting timer delay
timer.start(); // start the timer
}
public void switchDove() {
++doveIndex;
if (doveIndex >= IMAGEAMT)
doveIndex = 0;
if (isRight)
dove = doveRight[doveIndex];
else
dove = doveLeft[doveIndex];
dove = (isRight) ? doveRight[doveIndex] : doveLeft[doveIndex];
}
/** Handler for button clicks and timer events */
public void actionPerformed (ActionEvent evt) {
if (evt.getSource() == slowerButton)
{
DELAY += 10;
}
else if (evt.getSource() == reverseButton)
{
if(evt.getSource() == reverseButton && isRight == true){
isRight = false;
}
else if(evt.getSource() == reverseButton && !isRight){
isRight = true;
}
}
else if (evt.getSource() == fasterButton)
{
DELAY -= 10;
if (DELAY <= 10 ){
DELAY = 10;
}
}
else if (evt.getSource() == pauseResumeButton)
{
if(evt.getSource() == pauseResumeButton && !pause){
pauseResumeButton.setText(" Resume ");
timer.stop();
pause = true;
}
else if(evt.getSource() == pauseResumeButton && pause == true){
pauseResumeButton.setText(" Pause ");
timer.start();
pause = false;
}
}
else if (evt.getSource() == timer)
{
drawAnimation();
switchDove();
repaint();
}
}
/** Draws the dove in the dovePanel */
public void drawAnimation() {
Graphics page = dovePanel.getGraphics();
page.drawImage(dove,0,0,Color.WHITE,null);
}
/** The main method */
public static void main (String [] args) {
new DoveAnimator();
}
}
Yep it seems to be one of your repaint() calls. Take out your repaint() method call here:
else if (evt.getSource() == timer)
{
drawAnimation();
switchDove();
repaint();
It's confusing the program because you are already switching the doves. That's my best guess. I ran it and it seems to work though. Cheers!
Also I just noticed that the way you are adjusting your timer will yeild you no results. You need to use the command: timer.setDelay(newDelay); you can also put arguments in the parenthesis like timer.setDelay(DELAY -= 10);
I'm a beginner in BlackBerry programming, I need to replace in my application the default menu (when you press the menu button) by a custom menu, horizontal. The best to describe is I want the same result as the WeatherEye application for BlackBerry...
alt text http://www.blackberrybing.com/resource/pics/201002/WeatherEye-OS-45.jpg
I know how to create the default menu, but this one I have no idea!
Thank you,
What you will need to do is:
create SizebleVFManager (contentManager) as an extension of VerticalFieldManager
set display width and height = (display height - menu height) size to contentManager
add contentManager to screen
create HorizontalFieldManager (menuManager)
create BitmapButtonField (menuButton) as an extension of ButtonField
set FieldChangeListeners to menuButtons
add menuButtons to menuManager
add menuManager to screen
Sample of SizebleVFManager :
class SizebleVFManager extends VerticalFieldManager
{
int mWidth = 0;
int mHeight = 0;
public SizebleVFM(int width, int height, long style) {
super(style);
mWidth = width;
mHeight = height;
}
public SizebleVFM(int width, int height) {
mWidth = width;
mHeight = height;
}
public int getPreferredWidth() {
return mWidth;
}
public int getPreferredHeight() {
return mHeight;
}
protected void sublayout(int width, int height) {
width = getPreferredWidth();
height = getPreferredHeight();
super.sublayout(width, height);
setExtent(width, height);
}
}
...
SizebleVFManager contentManager =
new SizebleVFManager(Display.getWidth(), Display.getHeight(),
VERTICAL_SCROLL|VERTICAL_SCROLLBAR);
See also
sample of BitmapButtonField and Toolbar
PS though its better to use standard menu...
UPDATE
If you want to disable default menu functionality, cancel MENU keydown:
protected boolean keyDown(int keycode, int time) {
if(Keypad.KEY_MENU == Keypad.key(keycode))
{
return true;
}
else
return super.keyDown(keycode, time);
}
UPDATE
I've installed that wonderful weather application and understood this sample may be more alike with several improvements:
use CyclicHFManager as an extension of HorizontalFieldManager
show/hide menuManager on Menu button click
CyclicHFManager is a manager which will keep focus on the same place visually and run all fields over, in cycle. Like in BlackBerry - Custom centered cyclic HorizontalFieldManager
class CyclicHFManager extends HorizontalFieldManager {
int mFocusedFieldIndex = 0;
boolean mCyclicTurnedOn = false;
public void focusChangeNotify(int arg0) {
super.focusChangeNotify(arg0);
if (mCyclicTurnedOn) {
int focusedFieldIndexNew = getFieldWithFocusIndex();
if (focusedFieldIndexNew != mFocusedFieldIndex) {
if (focusedFieldIndexNew - mFocusedFieldIndex > 0)
switchField(0, getFieldCount() - 1);
else
switchField(getFieldCount() - 1, 0);
}
}
else
{
mFocusedFieldIndex = getFieldWithFocusIndex();
}
}
private void switchField(int prevIndex, int newIndex) {
Field field = getField(prevIndex);
delete(field);
insert(field, newIndex);
}
}
alt text http://img109.imageshack.us/img109/6176/toolbarj.jpg
And whole code sample:
abstract class AScreen extends MainScreen {
boolean mMenuEnabled = false;
SizebleVFManager mContentManager = null;
CyclicHFManager mMenuManager = null;
public AScreen() {
mContentManager = new SizebleVFManager(Display.getWidth(), Display
.getHeight(), VERTICAL_SCROLL | VERTICAL_SCROLLBAR);
add(mContentManager);
// mMenuManager = new CyclicHFManager(Display.getWidth(), 60);
mMenuManager = new CyclicHFManager();
mMenuManager.setBorder(BorderFactory.createBevelBorder(new XYEdges(4,
0, 0, 0), new XYEdges(Color.DARKBLUE, 0, 0, 0), new XYEdges(
Color.WHITE, 0, 0, 0)));
mMenuManager.setBackground(BackgroundFactory
.createLinearGradientBackground(Color.DARKBLUE, Color.DARKBLUE,
Color.LIGHTBLUE, Color.LIGHTBLUE));
for (int i = 0; i < 10; i++) {
Bitmap nBitmap = new Bitmap(60, 60);
Graphics g = new Graphics(nBitmap);
g.setColor(Color.DARKBLUE);
g.fillRect(0, 0, 60, 60);
g.setColor(Color.WHITE);
g.drawRect(0, 0, 60, 60);
Font f = g.getFont().derive(Font.BOLD, 40);
g.setFont(f);
String text = String.valueOf(i);
g.drawText(text, (60 - f.getAdvance(text)) >> 1, (60 - f
.getHeight()) >> 1);
Bitmap fBitmap = new Bitmap(60, 60);
g = new Graphics(fBitmap);
g.setColor(Color.DARKBLUE);
g.fillRect(0, 0, 60, 60);
g.setColor(Color.GOLD);
g.drawRect(0, 0, 60, 60);
g.setFont(f);
g.drawText(text, (60 - f.getAdvance(text)) >> 1, (60 - f
.getHeight()) >> 1);
BitmapButtonField button = new BitmapButtonField(nBitmap, fBitmap,
fBitmap);
button.setCookie(String.valueOf(i));
button.setPadding(new XYEdges(0, 18, 0, 18));
button.setChangeListener(new FieldChangeListener() {
public void fieldChanged(Field field, int context) {
Dialog.inform("Button # " + (String) field.getCookie());
}
});
mMenuManager.add(button);
}
}
protected boolean keyDown(int keycode, int time) {
if (Keypad.KEY_MENU == Keypad.key(keycode)) {
if (mMenuManager.getManager() != null) {
delete(mMenuManager);
mMenuManager.mCyclicTurnedOn = false;
mContentManager.updateSize(Display.getWidth(), Display
.getHeight());
} else {
add(mMenuManager);
mMenuManager.getField(2).setFocus();
mMenuManager.mCyclicTurnedOn = true;
mContentManager.updateSize(Display.getWidth(), Display
.getHeight()
- mMenuManager.getHeight());
}
return true;
} else
return super.keyDown(keycode, time);
}
}
class FirstScreen extends AScreen {
public FirstScreen() {
mContentManager.add(new LabelField("This is a first screen"));
}
}
public class ToolbarMenuApp extends UiApplication {
public ToolbarMenuApp() {
pushScreen(new FirstScreen());
}
public static void main(String[] args) {
(new ToolbarMenuApp()).enterEventDispatcher();
}
}