Making the RichTextField Horizontally Centered in Blackberry - layout

My current Mainscreen looks like :
The current code for each line of display is like:
RichTextField WeFix1 = new RichTextField("• Computer & Laptop", RichTextField.TEXT_JUSTIFY_HCENTER);
VFMTitle1 = new VerticalFieldManager(Field.USE_ALL_WIDTH| Field.NON_FOCUSABLE);
HFMTitle1 = new HorizontalFieldManager(FIELD_HCENTER);
HFMTitle1.add(WeFix1);
VFMTitle1.add(HFMTitle1);
add(VFMTitle21);
But need to it be positioned in a straight line :

There are many possibilities. You can adjust the margin of the container that holds list of services. Also you can make your custom field manager, and many more.
Option 1: Adjusting margin
VerticalFieldManager vfmServices = new VerticalFieldManager(VerticalFieldManager.USE_ALL_WIDTH);
vfmServices.add(new RichTextField("• Computer & Laptop"));
vfmServices.add(new RichTextField("• Modem / Router / Switches"));
vfmServices.add(new RichTextField("• Printer / Scanner"));
vfmServices.add(new RichTextField("• Tablet"));
final int horizontalMargin = 30;
vfmServices.setMargin(0, horizontalMargin, 0, horizontalMargin);
add(vfmServices);
Option 2: Using a custom field Manger
VerticalFieldManager vfmServiceLists = new VerticalFieldManager(VerticalFieldManager.USE_ALL_WIDTH);
vfmServiceLists.add(new RichTextField("• Computer & Laptop"));
vfmServiceLists.add(new RichTextField("• Modem / Router / Switches"));
vfmServiceLists.add(new RichTextField("• Printer / Scanner"));
vfmServiceLists.add(new RichTextField("• Tablet"));
Manager mListContainer = new Manager(Manager.USE_ALL_WIDTH) {
final int horizontalMargin = 30;
protected void sublayout(int width, int height) {
// this manager designed to contain only one list container.
if (getFieldCount() == 1) {
Field child = getField(0);
layoutChild(child, width - 2 * horizontalMargin, height);
// adjust manager height.
height = child.getHeight();
setPositionChild(child, horizontalMargin, 0);
}
setExtent(width, height);
}
};
mListContainer.add(vfmServiceLists);
add(mListContainer);
[Added Later]
As alishaik786 suggested in comment, if you use LabelField instead of RichTextField, you can check following code, which doesn't use any margin:
VerticalFieldManager vfmServiceLists = new VerticalFieldManager();
vfmServiceLists.add(new LabelField("• Computer & Laptop"));
vfmServiceLists.add(new LabelField("• Modem / Router / Switches"));
vfmServiceLists.add(new LabelField("• Printer / Scanner"));
vfmServiceLists.add(new LabelField("• Tablet"));
Manager mListContainer = new Manager(Manager.USE_ALL_WIDTH) {
protected void sublayout(int width, int height) {
// this manager designed to contain only one list container.
if (getFieldCount() == 1) {
Field child = getField(0);
layoutChild(child, width, height);
// adjust manager height.
height = child.getHeight();
setPositionChild(child, (width - child.getWidth()) / 2, 0);
}
setExtent(width, height);
}
};
mListContainer.add(vfmServiceLists);
add(mListContainer);

Better to use LabelField instead of RichTextField.
If you want the result on only RichTextField the below code is not suit for you; Then try to use our "Rupak" code;
This below code uses LabelField instead of RichTextField;
public class Abc extends MainScreen
{
VerticalFieldManager vertical;
Font font=Font.getDefault().derive(Font.BOLD, 18),small_font=Font.getDefault().derive(Font.PLAIN, 15);
LabelField labelField,labelFieldTwo;
public Abc()
{
createGUI();
}
private void createGUI()
{
vertical=new VerticalFieldManager(USE_ALL_WIDTH);
vertical.setBackground(BackgroundFactory.createSolidBackground(Color.GREEN));
HorizontalFieldManager hor=new HorizontalFieldManager(Field.FIELD_HCENTER);
hor.add(new LabelField(" We Fix ", Field.NON_FOCUSABLE));
hor.setFont(font);
hor.setPadding(5, 0, 5, 0);
vertical.add(hor);
HorizontalFieldManager hr=new HorizontalFieldManager(Field.FIELD_HCENTER);
hr.add(new LabelField("."));
hr.add(new LabelField("Computer Science & Laptop", Field.NON_FOCUSABLE));
hr.setFont(small_font);
vertical.add(hr);
HorizontalFieldManager hr1=new HorizontalFieldManager(Field.FIELD_HCENTER);
hr1.add(new LabelField("."));
hr1.add(new LabelField("Modem/Router/Switches", Field.NON_FOCUSABLE));
hr1.setFont(small_font);
vertical.add(hr1);
//------------------- Up to now you want like this; and you can do like this type also like left align and right align;
HorizontalFieldManager hr2=new HorizontalFieldManager(Field.FIELD_LEFT);
hr2.add(new LabelField("."));
hr2.add(new LabelField("Printer/Scanner", Field.NON_FOCUSABLE));
hr2.setFont(small_font);
vertical.add(hr2);
HorizontalFieldManager hr3=new HorizontalFieldManager(Field.FIELD_LEFT);
hr3.add(new LabelField("."));
hr3.add(new LabelField("Tablet", Field.NON_FOCUSABLE));
hr3.setFont(small_font);
vertical.add(hr3);
HorizontalFieldManager hr4=new HorizontalFieldManager(Field.FIELD_RIGHT);
hr4.add(new LabelField("."));
hr4.add(new LabelField("Printer/Scanner", Field.NON_FOCUSABLE));
hr4.setFont(small_font);
vertical.add(hr4);
HorizontalFieldManager hr5=new HorizontalFieldManager(Field.FIELD_RIGHT);
hr5.add(new LabelField("."));
hr5.add(new LabelField("Tablet", Field.NON_FOCUSABLE));
hr5.setFont(small_font);
vertical.add(hr5);
vertical.setPadding(0, 0, 10, 0);
add(vertical);
}
}
I got like this when field align center, right and left:

Try this..
LabelField lbl=new LabelField("• Computer & Laptop\r\n• Modem / Router / Switches\r\n•
Printer / Scanner\r\n• Tablet",LabelField.FIELD_HCENTER);

Related

Replacing System.Drawing with ImageSharp for Barcode .net core 6

As we have upgraded to net core 6 we are rewriting some of our code base. We have a tag helper in AspNet Core which generates a barcode. This currently uses System.Drawing and ZXing.
TagHelper Old version using System.Drawing - working (top barcode)
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var margin = 0;
var qrCodeWriter = new ZXing.BarcodeWriterPixelData
{
Format = ZXing.BarcodeFormat.PDF_417,
Options = new ZXing.Common.EncodingOptions
{
Height = this.Height > 80 ? this.Height : 80,
Width = this.Width > 400 ? this.Width : 400,
Margin = margin
}
};
var pixelData = qrCodeWriter.Write(QRCodeContent);
// creating a bitmap from the raw pixel data; if only black and white colors are used it makes no difference
// that the pixel data ist BGRA oriented and the bitmap is initialized with RGB
using (var bitmap = new Bitmap(pixelData.Width, pixelData.Height, System.Drawing.Imaging.PixelFormat.Format32bppRgb))
using (var ms = new MemoryStream())
{
var bitmapData = bitmap.LockBits(new Rectangle(0, 0, pixelData.Width, pixelData.Height),
System.Drawing.Imaging.ImageLockMode.WriteOnly, System.Drawing.Imaging.PixelFormat.Format32bppRgb);
try
{
// we assume that the row stride of the bitmap is aligned to 4 byte multiplied by the width of the image
System.Runtime.InteropServices.Marshal.Copy(pixelData.Pixels, 0, bitmapData.Scan0,
pixelData.Pixels.Length);
}
finally
{
bitmap.UnlockBits(bitmapData);
}
// save to stream as PNG
bitmap.Save(ms, System.Drawing.Imaging.ImageFormat.Png);
output.TagName = "img";
output.Attributes.Clear();
output.Attributes.Add("width", Width);
output.Attributes.Add("height", Height);
output.Attributes.Add("alt", Alt);
output.Attributes.Add("src",
$"data:image/png;base64,{Convert.ToBase64String(ms.ToArray())}");
}
}
TagHelper new version using ImageSharp - almost working but not exactly (bottom barcode)
public override void Process(TagHelperContext context, TagHelperOutput output)
{
var margin = 0;
var barcodeWriter = new ZXing.ImageSharp.BarcodeWriter<SixLabors.ImageSharp.PixelFormats.La32>
{
Format = ZXing.BarcodeFormat.PDF_417,
Options = new ZXing.Common.EncodingOptions
{
Height = this.Height > 80 ? this.Height : 80,
Width = this.Width > 400 ? this.Width : 400,
Margin = margin
}
};
var image = barcodeWriter.Write(QRCodeContent);
output.TagName = "img";
output.Attributes.Clear();
output.Attributes.Add("width", Width);
output.Attributes.Add("height", Height);
output.Attributes.Add("alt", Alt);
output.Attributes.Add("src", $"{image.ToBase64String(PngFormat.Instance)}");
}
The issue is as mentioned the 2nd barcode is very slightly different at the end seems to extend the last bar.
What am I missing?
That is a bug in the renderer implementation of the ZXing.Net binding to ImageSharp.
https://github.com/micjahn/ZXing.Net/issues/422
It is fixed in the newest nuget package of the bindings.
https://www.nuget.org/packages/ZXing.Net.Bindings.ImageSharp/
https://www.nuget.org/packages/ZXing.Net.Bindings.ImageSharp.V2/

How do I change the background color of a tabbed page in Xamarin iOS?

I need to change the background color of the currently tabbed page in my UITabBarController. I've searched through every stackoverflow post I could find but nothing worked for me. I thought there would be something like UITabBar.Appearance.SelectedImageTintColor, just for the background color but it doesn't seem so.
For example, I want to change the color of that part when I am on the right tab:
Does someone know how to do that?
You could invoked the following code in your UITabBarController
public xxxTabBarController()
{
//...set ViewControllers
this.TabBar.BarTintColor = UIColor.Red;
}
Update
//3.0 here is if you have three child page in tab , set it as the current value in your project
//
var size = new CGSize(TabBar.Frame.Width / 3.0, IsFullScreen());
this.TabBar.SelectionIndicatorImage = ImageWithColor(size,UIColor.Green);
double IsFullScreen()
{
double height = 64;
if (UIDevice.CurrentDevice.CheckSystemVersion(11, 0))
{
if (UIApplication.SharedApplication.Delegate.GetWindow().SafeAreaInsets.Bottom > 0.0)
{
height = 84;
}
}
return height;
}
UIImage ImageWithColor(CGSize size, UIColor color)
{
var rect = new CGRect(0, 0, size.Width, size.Height);
UIGraphics.BeginImageContextWithOptions(size, false, 0);
CGContext context = UIGraphics.GetCurrentContext();
context.SetFillColor(color.CGColor);
context.FillRect(rect);
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
The trick is to use the SelectionIndicatorImage Property of the UITabBar and generate a completely filled image with your desired color using the following method:
private UIImage ImageWithColor(CGSize size)
{
CGRect rect = new CGRect(0, 0, size.Width, size.Height);
UIGraphics.BeginImageContext(size);
using (CGContext context = UIGraphics.GetCurrentContext())
{
context.SetFillColor(UIColor.Green); //change color if necessary
context.FillRect(rect);
}
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
return image;
}
To initialize everything we override ViewWillLayoutSubviews() like this:
public override void ViewWillLayoutSubviews()
{
base.ViewWillLayoutSubviews();
// The tabbar height will always be 49 unless we force it to reevaluate it's size on runtime ...
myTabBar.InvalidateIntrinsicContentSize();
double height = myTabBar.Frame.Height;
CGSize size = new CGSize(new nfloat(myTabBar.Frame.Width / myTabBar.Items.Length, height));
// Now get our all-green image...
UIImage image = ImageWithColor(size);
// And set it as the selection indicator
myTabBar.SelectionIndicatorImage = image;
}
As mentioned in this article (google translating it step by step when necessary lol) calling InvalidateIntrinsicContentSize() will force the UITabBar to reevaluate it's size and will get you the actual runtime height of the tab bar (instead of the constant 49 height value from XCode).

Control image placement on JTextPane

I am able to add ImageIcons to a JTextPane, but when I add them they show up in the center of the JTextPane. I can't find a way to control where they are placed on the JTextPane. Can someone please help me with this?
This method is making the JTextPane:
private void loadTextPanel(JPanel contentPane) {
chatLogPanel = new JPanel();
chatLogPanel.setLayout(null);
EmptyBorder eb = new EmptyBorder(new Insets(10, 10, 10, 10));
DefaultStyledDocument document = new DefaultStyledDocument();
chatLog = new JTextPane(document);
chatLog.setEditorKit(new WrapEditorKit());
chatLog.setBorder(eb);
chatLog.setMargin(new Insets(5, 5, 5, 5));
chatLogScrollPane = new JScrollPane(chatLog);
addComponent(chatLogPanel, chatLogScrollPane, 0, 0, 500, 240);
addComponent(contentPane, chatLogPanel, 0, 40, 500, 240);
}
This is the code I'm using to add a string to the Panel:
private static void appendToChatLog(JTextPane tp, String msg, Color c) {
chatLog.setEditable(true);
StyleContext sc = StyleContext.getDefaultStyleContext();
AttributeSet aset = sc.addAttribute(SimpleAttributeSet.EMPTY, StyleConstants.Foreground, c);
aset = sc.addAttribute(aset, StyleConstants.FontFamily, "Lucida Console");
aset = sc.addAttribute(aset, StyleConstants.Alignment, Integer.valueOf(3));
int len = tp.getDocument().getLength();
tp.setCaretPosition(len);
tp.setCharacterAttributes(aset, false);
tp.replaceSelection(msg);
chatLog.setEditable(false);
}
And this is what I'm currently using to add the image to the JTextPane:
BufferedImage image = generateBufferedImage(message.getImage());
Icon icon = new ImageIcon(image);
StyleContext context = new StyleContext();
StyledDocument document = (StyledDocument) chatLog.getDocument();
Style labelStyle = context.getStyle(StyleContext.DEFAULT_STYLE);
JLabel label = new JLabel(icon);
StyleConstants.setComponent(labelStyle, label);
try {
document.insertString(document.getLength(), "Ignored", labelStyle);
} catch (BadLocationException badLocationException) {
badLocationException.printStackTrace();
}
To insert a component to a JTextPane, and display it like a character, use the insertComponent method.
To insert an Icon instead, use the insertIcon method.
Quite intuitive isn't it ;)

Zoom multiple sprites, individually on touch-Andengine

I am very new to andEngine, I want to add sprites on screen and let them move and zoom on finger touch.
Right now i am able to add multiple sprites on scene , and they can be dragged on touch.
Here is my code:
public class Main extends SimpleBaseGameActivity {
#Override
private Camera camera;
private BitmapTextureAtlas mBitmapTextureAtlas;
private ITextureRegion mFaceTextureRegion;
private ITextureRegion mFaceTextureRegion2;
private static final int CAMERA_WIDTH = 800;
private static final int CAMERA_HEIGHT = 480;
#Override
public EngineOptions onCreateEngineOptions() {
camera = new Camera(0, 0, CAMERA_WIDTH, CAMERA_HEIGHT);
EngineOptions engineOptions = new EngineOptions(true,
ScreenOrientation.LANDSCAPE_FIXED, new RatioResolutionPolicy(
CAMERA_WIDTH, CAMERA_HEIGHT), camera);
return engineOptions;
}
#Override
protected void onCreateResources() {
BitmapTextureAtlasTextureRegionFactory.setAssetBasePath("gfx/");
this.mBitmapTextureAtlas = new BitmapTextureAtlas(
this.getTextureManager(), 1024, 1600, TextureOptions.NEAREST);
// background
// this.background = new Sprite(0, 0,
// BitmapTextureAtlasTextureRegionFactory.createTiledFromAsset(this.mBitmapTextureAtlas,
// this, "ui_ball_1.png", 0, 0, 1, 1),
// this.getVertexBufferObjectManager());
this.mFaceTextureRegion = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(this.mBitmapTextureAtlas, this,
"ui_ball_1.png", 0, 0);
this.mFaceTextureRegion2 = BitmapTextureAtlasTextureRegionFactory
.createFromAsset(this.mBitmapTextureAtlas, this,
"ui_ball_1.png", 0, 0);
this.mBitmapTextureAtlas.load();
// this.mEngine.getTextureManager().loadTexture(this.mBitmapTextureAtlas);
/*
* this.mBitmapTextureAtlas = new
* BitmapTextureAtlas(this.getTextureManager(), 32, 32,
* TextureOptions.BILINEAR); this.mFaceTextureRegion =
* BitmapTextureAtlasTextureRegionFactory
* .createFromAsset(this.mBitmapTextureAtlas, this, "ui_ball_1.png", 0,
* 0); this.mBitmapTextureAtlas.load();
*/
}
#Override
protected Scene onCreateScene() {
/*
* this.scene = new Scene(); this.scene.attachChild(this.background);
* this.scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
* return this.scene;
*/
this.mEngine.registerUpdateHandler(new FPSLogger());
final Scene scene = new Scene();
scene.setBackground(new Background(0.09804f, 0.6274f, 0.8784f));
final float centerX = (CAMERA_WIDTH - this.mFaceTextureRegion
.getWidth()) / 2;
final float centerY = (CAMERA_HEIGHT - this.mFaceTextureRegion
.getHeight()) / 2;
final Sprite face = new Sprite(centerX, centerY,
this.mFaceTextureRegion, this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
return true;
}
};
face.setScale(2);
scene.attachChild(face);
scene.registerTouchArea(face);
final Sprite face2 = new Sprite(0, 0, this.mFaceTextureRegion2,
this.getVertexBufferObjectManager()) {
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
return true;
}
};
face2.setScale(2);
scene.attachChild(face2);
scene.registerTouchArea(face2);
scene.setTouchAreaBindingOnActionDownEnabled(true);
return scene;
}
}
Now i want to zoom each sprite on touch, but unable to find such method like setPosition available to move sprite to a specific position. Can anyone help me in achieving this without affecting the current functionality. Any help would be appreciated, may be in form of code or some direction/method to do this.
Thanks in advance :)
you can use a EntityModifier to make your effect:
#Override
public boolean onAreaTouched(final TouchEvent pSceneTouchEvent,
final float pTouchAreaLocalX, final float pTouchAreaLocalY) {
this.setPosition(pSceneTouchEvent.getX() - this.getWidth() / 2,
pSceneTouchEvent.getY() - this.getHeight() / 2);
this.clearEntityModifiers();
this.RegisterEntityModifier(new ScaleModifier(1f,2f,4f));
//1f = time to convert the scale of sprite of 2f to 4f
//2f = initial scale
//4f = finish scale
//when you dont touch the sprite back to normal scale
if(event.getAction()== MotionEvent.ACTION_UP) {
this.clearEntityModifiers();
this.RegisterEntityModifier(new ScaleModifier(1f,4f,2f));
}
//you also can work with "MotionEvent.ACTION_DOWN" and
//MotionEvent.ACTION_MOVE
return true;
}

App using MonoTouch Core Graphics mysteriously crashes

My app launches with a view controller and a simple view consisting of a button and a subview. When the user touches the button, the subview is populated with scrollviews that display the column headers, row headers, and cells of a spreadsheet. To draw the cells, I use CGBitmapContext to draw the cells, generate an image, and then put the image into the imageview contained in the scrollview that displays the cells.
When I run the app on the iPad, it displays the cells just fine, and the scrollview lets the user scroll around in the spreadsheet without any problems. If the user touches the button a second time, the spreadsheet redraws and continues to work perfectly, If, however, the user touches the button a third time, the app crashes. There is no exception information display in the Application Output window.
My first thought was that the successive button pushes were using up all the available memory, so I overrode the DidReceiveMemoryWarning method in the view controller and used a breakpoint to confirm that this method was not getting called. My next thought was that the CGBitmapContext was not getting released and looked for a Monotouch equivalent of Objective C's CGContextRelease() function. The closest I could find was the CGBitmapContext instance method Dispose(), which I called, without solving the problem.
In order to free up as much memory as possible (in case I was somehow running out of memory without tripping a warning), I tried forcing garbage collection each time I finished using a CGBitmapContext. This made the problem worse. Now the program would crash moments after displaying the spreadsheet the first time. This caused me to wonder whether the Garbage Collector was somehow collecting something necessary to the continued display of graphics on the screen.
I would be grateful for any suggestions on further avenues to investigate for the cause of these crashes. I have included the source code for the SpreadsheetView class. The relevant method is DrawSpreadsheet(), which is called when the button is touched.
Thank you for your assistance on this matter.
Stephen Ashley
public class SpreadsheetView : UIView
{
public ISpreadsheetMessenger spreadsheetMessenger = null;
public UIScrollView cellsScrollView = null;
public UIImageView cellsImageView = null;
public SpreadsheetView(RectangleF frame) : base()
{
Frame = frame;
BackgroundColor = Constants.backgroundBlack;
AutosizesSubviews = true;
}
public void DrawSpreadsheet()
{
UInt16 RowHeaderWidth = spreadsheetMessenger.RowHeaderWidth;
UInt16 RowHeaderHeight = spreadsheetMessenger.RowHeaderHeight;
UInt16 RowCount = spreadsheetMessenger.RowCount;
UInt16 ColumnHeaderWidth = spreadsheetMessenger.ColumnHeaderWidth;
UInt16 ColumnHeaderHeight = spreadsheetMessenger.ColumnHeaderHeight;
UInt16 ColumnCount = spreadsheetMessenger.ColumnCount;
// Add the corner
UIImageView cornerView = new UIImageView(new RectangleF(0f, 0f,
RowHeaderWidth, ColumnHeaderHeight));
cornerView.BackgroundColor = Constants.headingColor;
CGColorSpace cornerColorSpace = null;
CGBitmapContext cornerContext = null;
IntPtr buffer = Marshal.AllocHGlobal(RowHeaderWidth * ColumnHeaderHeight * 4);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory.");
try
{
cornerColorSpace = CGColorSpace.CreateDeviceRGB();
cornerContext = new CGBitmapContext
(buffer, RowHeaderWidth, ColumnHeaderHeight, 8, 4 * RowHeaderWidth,
cornerColorSpace, CGImageAlphaInfo.PremultipliedFirst);
cornerContext.SetFillColorWithColor(Constants.headingColor.CGColor);
cornerContext.FillRect(new RectangleF(0f, 0f, RowHeaderWidth, ColumnHeaderHeight));
cornerView.Image = UIImage.FromImage(cornerContext.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (cornerContext != null)
{
cornerContext.Dispose();
cornerContext = null;
}
if (cornerColorSpace != null)
{
cornerColorSpace.Dispose();
cornerColorSpace = null;
}
}
cornerView.Image = DrawBottomRightCorner(cornerView.Image);
AddSubview(cornerView);
// Add the cellsScrollView
cellsScrollView = new UIScrollView
(new RectangleF(RowHeaderWidth, ColumnHeaderHeight,
Frame.Width - RowHeaderWidth,
Frame.Height - ColumnHeaderHeight));
cellsScrollView.ContentSize = new SizeF
(ColumnCount * ColumnHeaderWidth,
RowCount * RowHeaderHeight);
Size iContentSize = new Size((int)cellsScrollView.ContentSize.Width,
(int)cellsScrollView.ContentSize.Height);
cellsScrollView.BackgroundColor = UIColor.Black;
AddSubview(cellsScrollView);
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
CGGradient gradient = null;
UIImage image = null;
int bytesPerRow = 4 * iContentSize.Width;
int byteCount = bytesPerRow * iContentSize.Height;
buffer = Marshal.AllocHGlobal(byteCount);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory.");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
context = new CGBitmapContext
(buffer, iContentSize.Width,
iContentSize.Height, 8, 4 * iContentSize.Width,
colorSpace, CGImageAlphaInfo.PremultipliedFirst);
float[] components = new float[]
{.75f, .75f, .75f, 1f,
.25f, .25f, .25f, 1f};
float[] locations = new float[]{0f, 1f};
gradient = new CGGradient(colorSpace, components, locations);
PointF startPoint = new PointF(0f, (float)iContentSize.Height);
PointF endPoint = new PointF((float)iContentSize.Width, 0f);
context.DrawLinearGradient(gradient, startPoint, endPoint, 0);
context.SetLineWidth(Constants.lineWidth);
context.BeginPath();
for (UInt16 i = 1; i <= RowCount; i++)
{
context.MoveTo
(0f, iContentSize.Height - i * RowHeaderHeight + (Constants.lineWidth/2));
context.AddLineToPoint((float)iContentSize.Width,
iContentSize.Height - i * RowHeaderHeight + (Constants.lineWidth/2));
}
for (UInt16 j = 1; j <= ColumnCount; j++)
{
context.MoveTo((float)j * ColumnHeaderWidth - Constants.lineWidth/2,
(float)iContentSize.Height);
context.AddLineToPoint((float)j * ColumnHeaderWidth - Constants.lineWidth/2, 0f);
}
context.StrokePath();
image = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (gradient != null)
{
gradient.Dispose();
gradient = null;
}
if (context != null)
{
context.Dispose();
context = null;
}
if (colorSpace != null)
{
colorSpace.Dispose();
colorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
UIImage finalImage = ActivateCell(1, 1, image);
finalImage = ActivateCell(0, 0, finalImage);
cellsImageView = new UIImageView(finalImage);
cellsImageView.Frame = new RectangleF(0f, 0f,
iContentSize.Width, iContentSize.Height);
cellsScrollView.AddSubview(cellsImageView);
}
private UIImage ActivateCell(UInt16 column, UInt16 row, UIImage backgroundImage)
{
UInt16 ColumnHeaderWidth = (UInt16)spreadsheetMessenger.ColumnHeaderWidth;
UInt16 RowHeaderHeight = (UInt16)spreadsheetMessenger.RowHeaderHeight;
CGColorSpace cellColorSpace = null;
CGBitmapContext cellContext = null;
UIImage cellImage = null;
IntPtr buffer = Marshal.AllocHGlobal(4 * ColumnHeaderWidth * RowHeaderHeight);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: ActivateCell()");
try
{
cellColorSpace = CGColorSpace.CreateDeviceRGB();
// Create a bitmap the size of a cell
cellContext = new CGBitmapContext
(buffer, ColumnHeaderWidth, RowHeaderHeight, 8,
4 * ColumnHeaderWidth, cellColorSpace, CGImageAlphaInfo.PremultipliedFirst);
// Paint it white
cellContext.SetFillColorWithColor(UIColor.White.CGColor);
cellContext.FillRect(new RectangleF(0f, 0f, ColumnHeaderWidth, RowHeaderHeight));
// Convert it to an image
cellImage = UIImage.FromImage(cellContext.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (cellContext != null)
{
cellContext.Dispose();
cellContext = null;
}
if (cellColorSpace != null)
{
cellColorSpace.Dispose();
cellColorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
// Draw the border on the cell image
cellImage = DrawBottomRightCorner(cellImage);
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
Size iContentSize = new Size((int)backgroundImage.Size.Width,
(int)backgroundImage.Size.Height);
buffer = Marshal.AllocHGlobal(4 * iContentSize.Width * iContentSize.Height);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: ActivateCell().");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
// Set up a bitmap context the size of the whole grid
context = new CGBitmapContext
(buffer, iContentSize.Width,
iContentSize.Height, 8, 4 * iContentSize.Width,
colorSpace, CGImageAlphaInfo.PremultipliedFirst);
// Draw the original grid into the bitmap
context.DrawImage(new RectangleF(0f, 0f, iContentSize.Width, iContentSize.Height),
backgroundImage.CGImage);
// Draw the cell image into the bitmap
context.DrawImage(new RectangleF(column * ColumnHeaderWidth,
iContentSize.Height - (row + 1) * RowHeaderHeight,
ColumnHeaderWidth, RowHeaderHeight),
cellImage.CGImage);
// Convert the bitmap back to an image
backgroundImage = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (context != null)
{
context.Dispose();
context = null;
}
if (colorSpace != null)
{
colorSpace.Dispose();
colorSpace = null;
}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
return backgroundImage;
}
private UIImage DrawBottomRightCorner(UIImage image)
{
int width = (int)image.Size.Width;
int height = (int)image.Size.Height;
float lineWidth = Constants.lineWidth;
CGColorSpace colorSpace = null;
CGBitmapContext context = null;
UIImage returnImage = null;
IntPtr buffer = Marshal.AllocHGlobal(4 * width * height);
if (buffer == IntPtr.Zero)
throw new OutOfMemoryException("Out of memory: DrawBottomRightCorner().");
try
{
colorSpace = CGColorSpace.CreateDeviceRGB();
context = new CGBitmapContext
(buffer, width, height, 8, 4 * width, colorSpace,
CGImageAlphaInfo.PremultipliedFirst);
context.DrawImage(new RectangleF(0f, 0f, width, height),
image.CGImage);
context.BeginPath();
context.MoveTo(0f, (int)(lineWidth/2f));
context.AddLineToPoint(width - (int)(lineWidth/2f), (int)(lineWidth/2f));
context.AddLineToPoint(width - (int)(lineWidth/2f), height);
context.SetLineWidth(Constants.lineWidth);
context.SetStrokeColorWithColor(UIColor.Black.CGColor);
context.StrokePath();
returnImage = UIImage.FromImage(context.ToImage());
}
finally
{
Marshal.FreeHGlobal(buffer);
if (context != null){
context.Dispose();
context = null;}
if (colorSpace != null){
colorSpace.Dispose();
colorSpace = null;}
// GC.Collect();
//GC.WaitForPendingFinalizers();
}
return returnImage;
}
}
Not sure if this will solve your problem (I'm even newer to this than you are), but it seems from this answer that MonoTouch prefers a different paradigm for creating/releasing graphics contexts, along the lines of:
UIGraphics.BeginImageContext(rect.Size)
var context = UIContext.GetCurrentContext();
// ... do stuff ...
UIImage image = UIGraphics.GetImageFromCurrentImageContext();
UIGraphics.EndImageContext();
// ... do something with image ...
I don't know if it's releasing everything properly, but otherwise it seems to work.

Resources