Hey I am newbie in xamarin and I working on a sample that requires imaging resizing using this tutorial http://sharpmobilecode.com/android-listviews-reinvented/. However when I add ImageManager. error says It cannot find assembly reference. Its not on System.Drawing also in Android.Drawing. I tried installing in nuget but it yields an error. thanks in advance and have a nice day.
ImageManager is a class that the tutorial implemented as well:
https://github.com/SharpMobileCode/ListViewsReinvented/blob/master/ListViewsReinvented.Droid/ImageManager.cs
So create a class and name it ImageManager, add the code below and change namespace to match yours:
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Android.Content.Res;
using Android.Graphics;
namespace ListViewsReinvented.Droid
{
public class ImageManager : IDisposable
{
private readonly Dictionary<int, Bitmap> _imageCache = new Dictionary<int, Bitmap>();
private Resources _resources;
public ImageManager(Resources resources)
{
_resources = resources;
}
private Task<BitmapFactory.Options> GetBitmapOptionsOfImageAsync(int resourceId)
{
return Task.Run(() => GetBitmapOptionsOfImage(resourceId));
}
private BitmapFactory.Options GetBitmapOptionsOfImage(int resourceId)
{
var options = new BitmapFactory.Options
{
InJustDecodeBounds = true
};
var result = BitmapFactory.DecodeResource(_resources, resourceId, options);
return options;
}
private int CalculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight)
{
float height = options.OutHeight;
float width = options.OutWidth;
double inSampleSize = 1D;
if (height > reqHeight || width > reqWidth)
{
int halfHeight = (int)(height / 2);
int halfWidth = (int)(width / 2);
while ((halfHeight / inSampleSize) > reqHeight && (halfWidth / inSampleSize) > reqWidth)
{
inSampleSize *= 2;
}
}
return (int)inSampleSize;
}
private Task<Bitmap> LoadScaledDownBitmapForDisplayAsync(BitmapFactory.Options options, int resourceId, int reqWidth, int reqHeight)
{
return Task.Run(() => LoadScaledDownBitmapForDisplay(options, resourceId, reqWidth, reqHeight));
}
private Bitmap LoadScaledDownBitmapForDisplay(BitmapFactory.Options options, int resourceId, int reqWidth, int reqHeight)
{
options.InSampleSize = CalculateInSampleSize(options, reqWidth, reqHeight);
options.InJustDecodeBounds = false;
var bitmap = BitmapFactory.DecodeResource(_resources, resourceId, options);
return bitmap;
}
public Task<Bitmap> GetScaledDownBitmapFromResourceAsync(int resourceId, int requiredWidth, int requiredHeight)
{
return Task.Run(() => GetScaledDownBitmapFromResource(resourceId, requiredWidth, requiredHeight));
}
public Bitmap GetScaledDownBitmapFromResource(int resourceId, int requiredWidth, int requiredHeight)
{
Bitmap bitmap;
if(_imageCache.TryGetValue(resourceId, out bitmap))
{
return bitmap;
}
var options = GetBitmapOptionsOfImage(resourceId);
bitmap = LoadScaledDownBitmapForDisplay(options, resourceId, requiredWidth, requiredHeight);
_imageCache.Add(resourceId, bitmap);
return bitmap;
}
#region IDisposable implementation
public void Dispose()
{
if(_imageCache == null)
return;
foreach(var key in _imageCache.Keys)
{
Bitmap bitmap;
if(_imageCache.TryGetValue(key, out bitmap))
{
Console.WriteLine(String.Format("Recycling bitmap {0} . . .", key));
bitmap.Recycle();
}
}
_imageCache.Clear();
}
#endregion
}
}
Related
The code works, but the images get trimmed off from the top. I have tried everything, but I still can't figure it out.
Can someone please take a look at it?
Thanks in advance.
Code:
public class ScalingUtilities {
public static Bitmap decodeResource(Resources res, int resId, int ReqWidth, int ReqHeight, ScalingLogic scalingLogic) {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeResource(res, resId, options);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, ReqWidth,
ReqHeight, scalingLogic);
Bitmap unscaledBitmap = BitmapFactory.decodeResource(res, resId, options);
return unscaledBitmap;
}
public static Bitmap decode_imagePath_String(String image_path, int ReqWidth, int ReqHeight, ScalingLogic scalingLogic) {
Options options = new Options();
options.inJustDecodeBounds = true;
BitmapFactory.decodeFile(image_path, options);
options.inJustDecodeBounds = false;
options.inSampleSize = calculateSampleSize(options.outWidth, options.outHeight, ReqWidth,
ReqHeight, scalingLogic);
Bitmap unscaledBitmap = BitmapFactory.decodeFile(image_path, options);
return unscaledBitmap;
}
public static Bitmap createScaledBitmap(Bitmap unscaledBitmap, int ReqWidth, int ReqHeight,
ScalingLogic scalingLogic) {
Rect srcRect = calculateSrcRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
ReqWidth, ReqHeight, scalingLogic);
Rect dstRect = calculateDstRect(unscaledBitmap.getWidth(), unscaledBitmap.getHeight(),
ReqWidth, ReqHeight, scalingLogic);
Bitmap scaledBitmap = Bitmap.createBitmap(dstRect.width(), dstRect.height(),
Config.RGB_565);
Canvas canvas = new Canvas(scaledBitmap);
canvas.drawBitmap(unscaledBitmap, srcRect, dstRect, new Paint(Paint.FILTER_BITMAP_FLAG));
return scaledBitmap;
}
public static enum ScalingLogic {
CROP, FIT
}
public static int calculateSampleSize(int srcWidth, int srcHeight, int ReqWidth, int ReqHeight,
ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float)srcWidth / (float)srcHeight;
final float dstAspect = (float)ReqWidth / (float)ReqHeight;
if (srcAspect > dstAspect) {
return srcWidth / ReqWidth;
} else {
return srcHeight / ReqHeight;
}
} else {
final float srcAspect = (float)srcWidth / (float)srcHeight;
final float dstAspect = (float)ReqWidth / (float)ReqHeight;
if (srcAspect > dstAspect) {
return srcHeight / ReqHeight;
} else {
return srcWidth / ReqWidth;
}
}
}
public static Rect calculateSrcRect(int srcWidth, int srcHeight, int ReqWidth, int ReqHeight,
ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.CROP) {
final float srcAspect = (float)srcWidth / (float)srcHeight;
final float dstAspect = (float)ReqWidth / (float)ReqHeight;
if (srcAspect > dstAspect) {
final int srcRectWidth = (int)(srcHeight * dstAspect);
final int srcRectLeft = (srcWidth - srcRectWidth) / 2;
return new Rect(srcRectLeft, 0, srcRectLeft + srcRectWidth, srcHeight);
} else {
final int srcRectHeight = (int)(srcWidth / dstAspect);
final int scrRectTop = (int)(srcHeight - srcRectHeight) / 2;
return new Rect(0, scrRectTop, srcWidth, scrRectTop + srcRectHeight);
}
} else {
return new Rect(0, 0, srcWidth, srcHeight);
}
}
public static Rect calculateDstRect(int srcWidth, int srcHeight, int ReqWidth, int ReqHeight,
ScalingLogic scalingLogic) {
if (scalingLogic == ScalingLogic.FIT) {
final float srcAspect = (float)srcWidth / (float)srcHeight;
final float dstAspect = (float)ReqWidth / (float)ReqHeight;
if (srcAspect > dstAspect) {
return new Rect(0, 0, ReqWidth, (int)(ReqWidth / srcAspect));
} else {
return new Rect(0, 0, (int)(ReqHeight * srcAspect), ReqHeight);
}
} else {
return new Rect(0, 0, ReqWidth, ReqHeight);
}
}
}
I very appreciate it...
In calculateSampleSize, you are returning int. Depending on the ratio of your image, this return value may very well be 0 and options.inSampleSize will be 0, so no scaling will take place.
Then the decode will decode with the size values you passed, so cropping will occur. I think that you need to use the density parameters instead. Please take a look at this post
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.
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);
}
});
}
}
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