I'm trying to draw a line based on touch event. Basically it draws line as the finger moves. I'm getting an error when overriding ontouchevent and onsizechanged. It was originally written in JAVA. I just translated it to C#. Here's the code:
protected override void OnCreate(Bundle bundle)
{
base.OnCreate(bundle);
currentLevel = Intent.GetIntExtra("gameLevel", 0);
playerScore = Intent.GetIntExtra("score", 0);
SetContentView(new SampleView(this));
// Create your application here
}
private class SampleView : View
{
private Paint mPaint;
private static Bitmap m_bitmap;
private DisplayMetrics m_metrics;
private Canvas m_canvas;
private Path m_path;
private Paint m_bitmapPaint;
private float m_X, m_Y;
static bool m_pathDrawn = false;
private static float TOUCH_TOLERANCE = 4;
public SampleView(Context context)
: base(context)
{
Focusable = true;
mPaint = new Paint();
mPaint.AntiAlias = true;
mPaint.Dither = true;
mPaint.SetStyle(Paint.Style.Stroke);
mPaint.StrokeWidth = 12;
mPaint.StrokeJoin = Paint.Join.Round;
mPaint.StrokeCap = Paint.Cap.Round;
m_metrics = context.Resources.DisplayMetrics;
m_bitmap = Bitmap.CreateBitmap(m_metrics.WidthPixels, m_metrics.HeightPixels, Bitmap.Config.Argb8888);
m_canvas = new Canvas(m_bitmap);
m_bitmapPaint = new Paint();
}
public void onerase()
{
m_canvas = null;
}
protected override void onSizeChanged(int p_w, int p_h, int p_oldw, int p_oldh)
{
this.onSizeChanged(p_w, p_h, p_oldw, p_oldh);
}
protected override void OnDraw(Canvas canvas)
{
canvas.DrawColor(Color.Black);
canvas.DrawBitmap(m_bitmap, 0, 0, m_bitmapPaint);
canvas.DrawPath(m_path, mPaint);
}
private void touch_start(float p_x, float p_y)
{
m_path.Reset();
m_path.MoveTo(p_x, p_y);
m_X = p_x;
m_Y = p_y;
}
private void touch_move(float p_x, float p_y)
{
float m_dx = Math.Abs(p_x - m_X);
float m_dy = Math.Abs(p_y - m_Y);
if (m_dx >= TOUCH_TOLERANCE || m_dy >= TOUCH_TOLERANCE)
{
m_path.QuadTo(m_X, m_Y, (p_x + m_X) / 2, (p_y + m_Y) / 2);
m_X = p_x;
m_Y = p_y;
m_pathDrawn = true;
}
}
private void touch_up()
{
m_path.LineTo(m_X, m_Y);
// commit the path to our offscreen
m_canvas.DrawPath(m_path, mPaint);
// kill this so we don't double draw
m_path.Reset();
}
public override bool onTouchEvent(MotionEvent p_event)
{
float m_x = p_event.GetX();
float m_y = p_event.GetY();
switch (p_event.Action)
{
case MotionEventActions.Down:
touch_start(m_x, m_y);
Invalidate();
break;
case MotionEventActions.Move:
touch_move(m_x, m_y);
Invalidate();
break;
case MotionEventActions.Up:
touch_up();
Invalidate();
break;
}
return true;
}
}
Another thing. I want to make my image view from a layout as my canvas and draw the line there ontouchevent. How should I do this? Thanks!
Method name should use pascal casing.
Android.Views.View.OnTouchEvent Method
Android.Views.View.OnSizeChanged Method
public override bool OnTouchEvent(MotionEvent e)
{
}
protected override void OnSizeChanged(int w, int h, int oldw, int oldh)
{
}
Mono coding guidelines.
Related
I'm creating a simple blackberry application for testing purposes and my custom buttons do not show on the UI of the simulator.
I've created a custom button called CustomButtonField and here is the code:
package test.expense;
import net.rim.device.api.ui.Field;
import net.rim.device.api.ui.Graphics;
public class CustomButtonField extends Field {
String label;
int backgroundColor;
int foregroundColor;
public CustomButtonField(String label, int backgroundColor, int foregroundColor, long style){
super(style);
this.label = label;
this.backgroundColor = backgroundColor;
this.foregroundColor = foregroundColor;
}
public int getPreferedHeight(){
return getFont().getHeight() + 8;
}
public int getPreferedWidth(){
return getFont().getAdvance(label) + 8;
}
protected void layout(int width, int height) {
setExtent(Math.min(width, getPreferredWidth()), Math.min(height, getPreferredHeight()));
}
protected void paint(Graphics graphics) {
graphics.setColor(backgroundColor);
graphics.fillRoundRect(1, 1, getWidth()-2, getHeight()-2, 12, 12);
graphics.setColor(foregroundColor);
graphics.drawText(label, 4, 4);
}
}
And here is where I invoke it and display it:
HorizontalFieldManager buttonManager = new HorizontalFieldManager(FIELD_RIGHT);
CustomButtonField btnCancel;
CustomButtonField btnSubmit;
public ExpenseSheetScreen() {
super();
btnCancel = new CustomButtonField("Cancel", Color.WHITE, 0x716eb3, 0);
btnCancel.setChangeListener(this);
btnSubmit = new CustomButtonField("Submit", Color.WHITE, 0x716eb3, 0);
btnSubmit.setChangeListener(this);
buttonManager.add(btnCancel);
buttonManager.add(btnSubmit);
add(buttonManager);
}// End Expense Sheet Screen.
What am I doing wrong?
protected void layout(int width, int height) {
setExtent(Math.min(width, getPreferredWidth()),
Math.min(height, getPreferredHeight()));
}
setExtend is set to 0, 0 all the time.
Do you know some way to programmaticaly show different typing indicators on the screen?
I know I can simply draw bitmap but I'd like to do it universally for any RIM OS version.
Also, there is a setMode(int) function in 4.2.1 but in 4.3 it's already deprecated...
Any suggestions will be helpful, thanks!
since there is no alternatives, I made a sample with provided images:
alt text http://img42.imageshack.us/img42/6692/typeindicator.jpg
alt text http://img3.imageshack.us/img3/5259/inputind.jpg
custom Title Field class code:
class TITitleField extends Field implements DrawStyle {
static final boolean mIsDimTheme = Integer.parseInt(DeviceInfo
.getDeviceName().substring(0, 4)) < 8900;
static final Bitmap ALT = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_alt_mode_Gen_Zen_328560_11.jpg" :
"typ_ind_alt_mode_Precsn_Zen_392908_11.jpg");
static final Bitmap MULTITAP = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_mltap_mode_Gen_Zen_328975_11.jpg" :
"typ_ind_mutlitap_mode_Precsn_Zen_452907_11.jpg");
static final Bitmap NUMLOCK = Bitmap
.getBitmapResource(mIsDimTheme ?
"typ_ind_num_lock_Gen_Zen_328568_11.jpg" :
"typ_ind_num_lock_Precsn_Zen_392925_11.jpg");
static final Bitmap SHIFT = Bitmap.getBitmapResource(mIsDimTheme ?
"typ_ind_shift_mode_Gen_Zen_328574_11.jpg" :
"typ_ind_shift_mode_Precsn_Zen_392931_11.jpg");
public static final int MODE_NONE = 0;
public static final int MODE_ALT = 1;
public static final int MODE_MULTITAP = 2;
public static final int MODE_NUMLOCK = 3;
public static final int MODE_SHIFT = 4;
public void setTypingIndicatorMode(int mode) {
mMode = mode;
updateLayout();
}
public int getTypingIndicatorMode()
{
return mMode;
}
int mWidth = 0;
int mMode = 0;
String mTitle = "";
XYRect mIndicatorDestRect = new XYRect();
public TITitleField() {
this("");
}
public TITitleField(String title) {
mTitle = title;
}
protected void paint(Graphics graphics) {
graphics.drawText(mTitle, 0, 0, LEFT | ELLIPSIS, mWidth);
if (0 != mMode) {
graphics.drawBitmap(mIndicatorDestRect,getIndicator(mMode),0,0);
}
}
private static Bitmap getIndicator(int mode) {
Bitmap result = null;
switch (mode) {
case MODE_ALT:
result = ALT;
break;
case MODE_MULTITAP:
result = MULTITAP;
break;
case MODE_NUMLOCK:
result = NUMLOCK;
break;
case MODE_SHIFT:
result = SHIFT;
break;
case MODE_NONE:
break;
default:
break;
}
return result;
}
protected void layout(int width, int height) {
mWidth = width;
if (0 != mMode) {
Bitmap indicator = getIndicator(mMode);
mIndicatorDestRect.width = indicator.getWidth();
mIndicatorDestRect.height = indicator.getHeight();
mIndicatorDestRect.y = 0;
mIndicatorDestRect.x = mWidth - mIndicatorDestRect.width;
}
setExtent(width, getPreferredHeight());
}
public int getPreferredHeight() {
int height = getFont().getHeight() + 4;
if (0 != mMode) {
int indicatorHeight = getIndicator(mMode).getHeight();
height = Math.max(height, indicatorHeight);
}
return height;
}
}
Sample of use code:
class Scr extends MainScreen {
static final TITitleField mTitle = new TITitleField("Start");
public Scr() {
this.setTitle(mTitle);
}
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
int typingIndicatorMode = mTitle.getTypingIndicatorMode();
if(typingIndicatorMode != mTitle.MODE_NONE)
menu.add(new MenuItem("None Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_NONE);
}
});
if(typingIndicatorMode != mTitle.MODE_ALT)
menu.add(new MenuItem("Alt Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_ALT);
}
});
if(typingIndicatorMode != mTitle.MODE_MULTITAP)
menu.add(new MenuItem("Multitap Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_MULTITAP);
}
});
if(typingIndicatorMode != mTitle.MODE_NUMLOCK)
menu.add(new MenuItem("NumLock Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_NUMLOCK);
}
});
if(typingIndicatorMode != mTitle.MODE_SHIFT)
menu.add(new MenuItem("Shift Mode", 0, 0) {
public void run() {
mTitle.setTypingIndicatorMode(mTitle.MODE_SHIFT);
}
});
}
}
It's easy to show some animation within one field - BitmapField or Screen:
[Blackberry - background image/animation RIM OS 4.5.0][1]
But what if you need to move fields, not just images?
May be used:
game workflow functionality, like chess, puzzle etc
application user-defined layout, like in Google gadgets
enhanced GUI animation effects
So, I'd like to exchange my expirience in this task, on the other hand, I'd like to know about any others possibilities and suggestions.
This effect may be easily achived with custom layout:
class AnimatedManager extends Manager {
int ANIMATION_NONE = 0;
int ANIMATION_CROSS_FLY = 1;
boolean mAnimationStart = false;
Bitmap mBmpBNormal = Bitmap.getBitmapResource("blue_normal.png");
Bitmap mBmpBFocused = Bitmap.getBitmapResource("blue_focused.png");
Bitmap mBmpRNormal = Bitmap.getBitmapResource("red_normal.png");
Bitmap mBmpRFocused = Bitmap.getBitmapResource("red_focused.png");
Bitmap mBmpYNormal = Bitmap.getBitmapResource("yellow_normal.png");
Bitmap mBmpYFocused = Bitmap.getBitmapResource("yellow_focused.png");
Bitmap mBmpGNormal = Bitmap.getBitmapResource("green_normal.png");
Bitmap mBmpGFocused = Bitmap.getBitmapResource("green_focused.png");
int[] width = null;
int[] height = null;
int[] xPos = null;
int[] yPos = null;
BitmapButtonField mBButton = new BitmapButtonField(mBmpBNormal,
mBmpBFocused);
BitmapButtonField mRButton = new BitmapButtonField(mBmpRNormal,
mBmpRFocused);
BitmapButtonField mYButton = new BitmapButtonField(mBmpYNormal,
mBmpYFocused);
BitmapButtonField mGButton = new BitmapButtonField(mBmpGNormal,
mBmpGFocused);
public AnimatedManager() {
super(USE_ALL_HEIGHT | USE_ALL_WIDTH);
add(mBButton);
add(mRButton);
add(mYButton);
add(mGButton);
width = new int[] { mBButton.getPreferredWidth(),
mRButton.getPreferredWidth(),
mYButton.getPreferredWidth(),
mGButton.getPreferredWidth() };
height = new int[] { mBButton.getPreferredHeight(),
mRButton.getPreferredHeight(),
mYButton.getPreferredHeight(),
mGButton.getPreferredHeight() };
xPos = new int[] { 0, getPreferredWidth() - width[1], 0,
getPreferredWidth() - width[3] };
yPos = new int[] { 0, 0, getPreferredHeight() - height[2],
getPreferredHeight() - height[3] };
Timer timer = new Timer();
timer.schedule(mAnimationTask, 0, 100);
}
TimerTask mAnimationTask = new TimerTask() {
public void run() {
UiApplication.getUiApplication().invokeLater(new Runnable() {
public void run() {
updateLayout();
};
});
};
};
MenuItem mAnimationMenuItem = new MenuItem("Start", 0, 0) {
public void run() {
mAnimationStart = true;
};
};
protected void makeMenu(Menu menu, int instance) {
super.makeMenu(menu, instance);
menu.add(mAnimationMenuItem);
}
public int getPreferredHeight() {
return Display.getHeight();
}
public int getPreferredWidth() {
return Display.getWidth();
}
protected void sublayout(int width, int height) {
width = getPreferredWidth();
height = getPreferredHeight();
if (getFieldCount() > 3) {
Field first = getField(0);
Field second = getField(1);
Field third = getField(2);
Field fourth = getField(3);
layoutChild(first, this.width[0], this.height[0]);
layoutChild(second, this.width[1], this.height[1]);
layoutChild(third, this.width[2], this.height[2]);
layoutChild(fourth, this.width[3], this.height[3]);
if (mAnimationStart) {
boolean anim1 = performLayoutAnimation(0,
width - this.width[0],
height - this.height[0]);
boolean anim2 = performLayoutAnimation(1, 0,
height - this.height[1]);
boolean anim3 = performLayoutAnimation(2,
width - this.width[2], 0);
boolean anim4 = performLayoutAnimation(3, 0, 0);
mAnimationStart = anim1 || anim2 || anim3 || anim4;
}
setPositionChild(first, xPos[0], yPos[0]);
setPositionChild(second, xPos[1], yPos[1]);
setPositionChild(third, xPos[2], yPos[2]);
setPositionChild(fourth, xPos[3], yPos[3]);
}
setExtent(width, height);
}
boolean performLayoutAnimation(int fieldIndex, int x, int y) {
boolean result = false;
if (xPos[fieldIndex] > x) {
xPos[fieldIndex] -= 2;
result = true;
} else if (xPos[fieldIndex] < x) {
xPos[fieldIndex] += 2;
result = true;
}
if (yPos[fieldIndex] > y) {
yPos[fieldIndex] -= 1;
result = true;
} else if (yPos[fieldIndex] < y) {
yPos[fieldIndex] += 1;
result = true;
}
return result;
}
}
BitmapButtonField class I've used:
class BitmapButtonField extends ButtonField {
Bitmap mNormal;
Bitmap mFocused;
int mWidth;
int mHeight;
public BitmapButtonField(Bitmap normal, Bitmap focused) {
super(CONSUME_CLICK);
mNormal = normal;
mFocused = focused;
mWidth = mNormal.getWidth();
mHeight = mNormal.getHeight();
setMargin(0, 0, 0, 0);
setPadding(0, 0, 0, 0);
setBorder(BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
setBorder(VISUAL_STATE_ACTIVE, BorderFactory
.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
}
protected void paint(Graphics graphics) {
Bitmap bitmap = null;
switch (getVisualState()) {
case VISUAL_STATE_NORMAL:
bitmap = mNormal;
break;
case VISUAL_STATE_FOCUS:
bitmap = mFocused;
break;
case VISUAL_STATE_ACTIVE:
bitmap = mFocused;
break;
default:
bitmap = mNormal;
}
graphics.drawBitmap(0, 0, bitmap.getWidth(), bitmap.getHeight(),
bitmap, 0, 0);
}
public int getPreferredWidth() {
return mWidth;
}
public int getPreferredHeight() {
return mHeight;
}
protected void layout(int width, int height) {
setExtent(mWidth, mHeight);
}
protected void applyTheme(Graphics arg0, boolean arg1) {
}
}
I need to display a custom icon and two hyperlinks in model pop up on Blackberry map. How can I do this?
alt text http://img689.imageshack.us/img689/2886/maplinkicon.jpg
First implement extention of ButtonField which will:
look like icon
on click will open Browser with predefined link
will use context menu
Code for such control:
class MapLinkIcon extends ButtonField implements FieldChangeListener {
Bitmap mNormal;
Bitmap mFocused;
String mLink;
String mDescription;
int mWidth;
int mHeight;
public MapLinkIcon(Bitmap normal, Bitmap focused, String link,
String description) {
super(CONSUME_CLICK);
mNormal = normal;
mFocused = focused;
mLink = link;
mDescription = description;
mWidth = mNormal.getWidth();
mHeight = mNormal.getHeight();
setMargin(0, 0, 0, 0);
setPadding(0, 0, 0, 0);
setBorder(BorderFactory.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
setBorder(VISUAL_STATE_ACTIVE, BorderFactory
.createSimpleBorder(new XYEdges(0, 0, 0, 0)));
this.setChangeListener(this);
}
protected void paint(Graphics graphics) {
Bitmap bitmap = null;
switch (getVisualState()) {
case VISUAL_STATE_NORMAL:
bitmap = mNormal;
break;
case VISUAL_STATE_FOCUS:
bitmap = mFocused;
break;
case VISUAL_STATE_ACTIVE:
bitmap = mFocused;
break;
default:
bitmap = mNormal;
}
graphics.drawBitmap(0, 0, bitmap.getWidth(), bitmap.getHeight(),
bitmap, 0, 0);
}
public int getPreferredWidth() {
return mWidth;
}
public int getPreferredHeight() {
return mHeight;
}
protected void layout(int width, int height) {
setExtent(mWidth, mHeight);
}
protected void applyTheme(Graphics arg0, boolean arg1) {
}
public void fieldChanged(Field field, int context) {
openLink(mLink);
}
MenuItem mMenuItem = new MenuItem("Go To Link", 0, 0) {
public void run() {
openLink(mLink);
}
};
protected void makeContextMenu(ContextMenu contextMenu) {
super.makeContextMenu(contextMenu);
contextMenu.addItem(mMenuItem);
}
private static void openLink(String link) {
Browser.getDefaultSession().displayPage(link);
}
}
Now we can use this button control in combination with MapField, override sublayout to place button over the map:
class CustomMapField extends VerticalFieldManager {
MapField mMapField;
MapLinkIcon mButton;
public CustomMapField() {
add(mMapField = new MapField());
}
public int getPreferredHeight() {
return getScreen().getHeight();
}
public int getPreferredWidth() {
return getScreen().getWidth();
}
public void moveTo(Coordinates coordinates, Bitmap icoNorm, Bitmap icoAct,
String link, String description) {
mMapField.moveTo(coordinates);
add(mButton = new MapLinkIcon(icoNorm, icoAct, link, description));
}
protected void sublayout(int maxWidth, int maxHeight) {
int width = getPreferredWidth();
int height = getPreferredHeight();
layoutChild(mMapField, width, height);
setPositionChild(mMapField, 0, 0);
layoutChild(mButton, mButton.mWidth, mButton.mHeight);
XYPoint fieldOut = new XYPoint();
mMapField.convertWorldToField(mMapField.getCoordinates(), fieldOut);
int xPos = fieldOut.x - mButton.mWidth / 2;
int yPos = fieldOut.y - mButton.mHeight;
setPositionChild(mButton, xPos, yPos);
setExtent(width, height);
}
}
Example of use:
class Scr extends MainScreen {
CustomMapField mMapField;
Coordinates mCoordinates;
public Scr() {
double latitude = 51.507778;
double longitude = -0.128056;
mCoordinates = new Coordinates(latitude, longitude, 0);
mMapField = new CustomMapField();
Bitmap icoNormal = Bitmap.getBitmapResource("so_icon_normal.png");
Bitmap icoActive = Bitmap.getBitmapResource("so_icon_active.png");
String link = "http://stackoverflow.com";
String description = "StackOverflow";
mMapField.moveTo(mCoordinates, icoNormal, icoActive, link, description);
add(mMapField);
}
}
See also:
How to show our own icon in BlackBerry Map?
How to show more than one location in Blackberry MapField?
Please help me, how to set a background image for screen and How to do animations on any-field or on text?
Thank You....
Background image
In Screen class there is a protected void paintBackground(Graphics graphics) method.
By some reason we can't use it directly to paint background image in screen. The catch: paintBackground method is derived from Field class, and we can use it in VerticalFieldManager on example:
class BgScreen extends MainScreen implements FieldChangeListener {
ButtonField mButton;
public BgScreen(Bitmap background) {
super();
BGVerticalFieldManager manager =
new BGVerticalFieldManager(background);
add(manager);
mButton = new ButtonField("Button", ButtonField.CONSUME_CLICK);
mButton.setChangeListener(this);
manager.add(mButton);
}
public void fieldChanged(Field field, int context) {
if (mButton == field)
Dialog.inform("You pressed button");
}
}
class BGVerticalFieldManager extends VerticalFieldManager {
Bitmap mBgBitmap = null;
int mBgWidth = -1;
int mBgHeight = -1;
int mBgX = -1;
int mBgY = -1;
public BGVerticalFieldManager(Bitmap background) {
super(USE_ALL_WIDTH | USE_ALL_HEIGHT);
mBgBitmap = background;
mBgWidth = mBgBitmap.getWidth();
mBgHeight = mBgBitmap.getHeight();
mBgX = (Display.getWidth() - mBgWidth) >> 1;
mBgY = (Display.getHeight() - mBgHeight) >> 1;
}
protected void paintBackground(Graphics graphics) {
paintBackgroundBitmap(graphics);
super.paintBackground(graphics);
}
private void paintBackgroundBitmap(Graphics graphics) {
if (null != mBgBitmap) {
graphics.drawBitmap(
mBgX, mBgY, mBgWidth, mBgHeight, mBgBitmap, 0, 0);
}
}
}
GIF animation
To use GIF animation, override protected void paint(Graphics graphics) method and use drawImage of incremented frame index. Use Timer.scheduleAtFixedRate to invalidate field:
class GIFVerticalFieldManager extends VerticalFieldManager {
EncodedImage mGIFImage = null;
int mGIFWidth = -1;
int mGIFHeight = -1;
int mGIFX = -1;
int mGIFY = -1;
int mGIFFrameCount = -1;
int mGIFFrameIndex = -1;
final int mGIFDelay = 30;
public GIFVerticalFieldManager(EncodedImage gifAnimation) {
super(USE_ALL_WIDTH | USE_ALL_HEIGHT);
mGIFImage = gifAnimation;
mGIFWidth = mGIFImage.getWidth();
mGIFHeight = mGIFImage.getHeight();
mGIFX = (Display.getWidth() - mGIFWidth) >> 1;
mGIFY = (Display.getHeight() - mGIFHeight) >> 1;
mGIFFrameCount = mGIFImage.getFrameCount();
mGIFFrameIndex = 0;
Timer timer = new Timer();
timer.scheduleAtFixedRate(new TimerTask() {
public void run() {
invalidate();
}
}, mGIFDelay, mGIFDelay);
}
protected void paint(Graphics graphics) {
paintGifAnimation(graphics);
super.paint(graphics);
}
private void paintGifAnimation(Graphics graphics) {
if (null != mGIFImage) {
graphics.drawImage(
mGIFX, mGIFY, mGIFWidth, mGIFHeight,
mGIFImage, mGIFFrameIndex, 0, 0);
mGIFFrameIndex++;
if (mGIFFrameIndex > mGIFFrameCount - 1)
mGIFFrameIndex = 0;
}
}
}
EDIT: Great article - Direct Screen Drawing