NSAttributedString using NSSuperscriptAttributeName in Xamarin iOS - ios

Hi Im trying to get the superscript attribute to work with a UILabel in a xamarin iOS app. I have the following code, Im using a sketches right now just to see how it looks, so should be easy to copy/paste :D :
using UIKit;
using Foundation;
using CoreGraphics;
var label = new UILabel( new CGRect(0,0,UIScreen.MainScreen.Bounds.Width, UIScreen.MainScreen.Bounds.Height));
label.Text = "100.0o";
label.TextAlignment = UITextAlignment.Center;
var prettyString = new NSMutableAttributedString ("UITextField is not pretty!");
prettyString.AddAttribute (UIStringAttributeKey.SuperscriptAttributeName, NSNumber.FromDouble (1.0), new NSRange (prettyString.Length -1 , 1));
label.AttributedText = prettyString;
RootView.Add(label);
I can see from here that it is available in MonoMac.Foundation. Does anyone know how to get that string in iOS as it doesn't seem to be available from UIKit.UIStringAttributeKey.

From this answer I was able to use UIStringAttributeKey.BaselineOffset like so:
// Sketch your next great idea!
using UIKit;
using Foundation;
using CoreGraphics;
using CoreText;
var slider = new UISlider (new CGRect(0,UIScreen.MainScreen.Bounds.Height-30,UIScreen.MainScreen.Bounds.Width, 30.0f));
slider.MinValue = 10.0f;
slider.MaxValue = 120.0f;
var h = 65.0f;
var label = new UILabel( new CGRect(0,h,UIScreen.MainScreen.Bounds.Width, h*2));
var firstAttributes = new UIStringAttributes ();
var secondAttributes = new UIStringAttributes ();
var prettyString = new NSMutableAttributedString ("99.99°");
var label2 = new UILabel( new CGRect(0,h*3,UIScreen.MainScreen.Bounds.Width, h));
slider.ValueChanged += (object sender, EventArgs e) =>
{
h = slider.Value;
label.Text = slider.Value.ToString ();
label.Frame = new CGRect(0,h,UIScreen.MainScreen.Bounds.Width, h*2);
label.TextAlignment = UITextAlignment.Center;
label.Font = UIFont.FromName("Helvetica", h);
firstAttributes = new UIStringAttributes (new NSDictionary(
// Can set this to >1.0 to make it higher but was too high for me.
// CTStringAttributeKey.Superscript, NSNumber.FromDouble (0.0),
UIStringAttributeKey.Font ,UIFont.FromName("Helvetica", h),
UIStringAttributeKey.BackgroundColor ,UIColor.FromRGBA (0.0f, 1.0f, 1.0f, 0.2f)
));
secondAttributes = new UIStringAttributes (new NSDictionary(
UIStringAttributeKey.Font ,UIFont.FromName("Helvetica", h/2),
UIStringAttributeKey.BackgroundColor ,UIColor.FromRGBA (1.0f, 0.0f, 1.0f, 0.2f),
UIStringAttributeKey.BaselineOffset, NSNumber.FromDouble (h/3)
));
prettyString.SetAttributes (firstAttributes.Dictionary, new NSRange (1, prettyString.Length-1));
prettyString.SetAttributes (secondAttributes.Dictionary, new NSRange (prettyString.Length-1, 1));
label.AttributedText = prettyString;
label2.Frame = new CGRect(0,h*3,UIScreen.MainScreen.Bounds.Width, h);
label2.Text = "99.99°";
label2.TextAlignment = UITextAlignment.Center;
label2.Font = UIFont.FromName("Helvetica", h);
};
RootView.Add(slider);
RootView.Add(label);
RootView.Add(label2);

Related

I'm having problems zooming into images that are in rows of an UITableView in Xamarin.iOS

I have a tableView inside a tabView, and my rows in the tableView contain images. I would like to zoom into the said images (I put them inside a scrollView and set the max/min zoom and I set ViewForZoomingInScrollView), but it seems I can't get the zoom to trigger because they are small images 50x56 or some other gesture/event is interfeiring. I use the same zoom code on another part of my app and it works perfectly. Has anyone come across the same or similar problem or knows a possible solution?
EDIT:
protected DocumentBaseCell()
: base(UITableViewCellStyle.Default, new NSString("TableCell"))
{
...
documentImage = new UIImageView();
documentImage.Image = UIImage.FromBundle("LaunchImage");
documentImage.ContentMode = UIViewContentMode.ScaleAspectFit;
documentImage.Layer.ZPosition = 0;
imageScrollView = new UIScrollView();
imageScrollView.ClipsToBounds = false;
imageScrollView.ContentSize = new CGSize(50, 56);
imageScrollView.MaximumZoomScale = 8f;
imageScrollView.MinimumZoomScale = 1f;
imageScrollView.Add(documentImage);
imageScrollView.ViewForZoomingInScrollView += (UIScrollView sv) =>
{
imageScrollView.ContentSize = new CGSize(documentImage.Frame.Width, documentImage.Frame.Height);
return documentImage;
};
imageScrollView.DidZoom += (object sender, EventArgs e) =>
{
//(sender as UIView).Layer.ZPosition = 2000;
};
imageScrollView.ZoomingEnded += (object sender, ZoomingEndedEventArgs e) =>
{
(sender as UIScrollView).SetZoomScale(0f, true);
(sender as UIView).Layer.ZPosition = 0;
this.Layer.ZPosition = 0;
};
ContentView.Add(imageScrollView);
...
}
And this is the UpdateCell method:
internal virtual void UpdateCell(DocumentModel doc, string sup, string
docType, string user, string date, UIImage image)
{
if (image != null)
{
this.documentImage.Image = image;
}
...
}
The Frame is set aswell:
public override void LayoutSubviews()
{
base.LayoutSubviews();
imageScrollView.Frame = new CGRect(0, 2, 50, 56);
documentImage.Frame = new CGRect(0, 0, 50, 56);
}
I think you should give a frame to imageScrollView and documentImage, I download the official tableView sample project and add your code there, it zooms well.
public override void LayoutSubviews ()
{
base.LayoutSubviews ();
imageScrollView.Frame = new CGRect(ContentView.Bounds.Width - 233, 5, 133, 133);
headingLabel.Frame = new CGRect(5, 4, ContentView.Bounds.Width - 63, 25);
subheadingLabel.Frame = new CGRect(100, 18, 100, 20);
imageView.Frame = imageScrollView.Bounds;
}
I uploaded a sample project here and you can check it.

Monotouch - Use a for loop to create UILabels programmatically below each other

I know the solution may be fairly simple, but I'm having challenges with positioning these views.
I'm trying to create UILabels dynamically, within a UITableViewCell. The number of UILabels is unknown at compile time.
Based on the size of my list of data, I would like to create a new UILabel, one below another and populate the data at each index in the list, on the respective UILabel.
Because these are created inside a UITableViewCell, I would like them to be positioned below the cell's TextLabel.
Currently, my new UILabels are all stacked on top of each other, above the TextLabel and I can't seem to position them correctly.
public void UpdateCell(List<Records> allRecords,List<string> otherInfo)
{
try{
UILabel label = new UILabel();
myRecords = allRecords;
for(int i = 0; i < myRecords.Count;i++)
{
if(i == 0)
//Position the first one below the cell's TextLabel
{
string time = myRecords[i].ResponseTime;
label.Frame = new CoreGraphics.CGRect(TextLabel.Frame.X + 10,TextLabel.Frame.Y + TextLabel.Frame.Height + 10,ContentView.Frame.Width,19);
label.Font = UIFont.FromName ("HelveticaNeueLTStd-ThCn", 18f);
label.TextColor = UIColor.DarkGray;
label.Text = string.Format("- {0}, {1}",otherInfo[i],time);
ContentView.AddSubview(label);
}else{
string responseTime = myRecords[i].ResponseTime;
//Position subsequent views below the first label
UILabel label1 = new UILabel();
label1.Frame = new CoreGraphics.CGRect(label.Frame.X,label.Frame.Bottom + 5,ContentView.Frame.Width,19);
label1.Font = UIFont.FromName ("HelveticaNeueLTStd-ThCn", 18f);
label1.TextColor = UIColor.DarkGray;
label1.Text = string.Format("- {0}, {1}",otherInfo[i],responseTime);
ContentView.AddSubview(label1);
}
}
}
}catch(Exception ex)
{
Console.WriteLine (ex.Message + ex.StackTrace);
}
}
Based on the answer on SO here : How to create n number of UIButton programmatically in UITableView Cell?
I was able to come up with a solution like this:
public void UpdateCell(List<Records> allRecords,List<string> otherInfo)
{
try{
UILabel label = new UILabel();
myRecords = allRecords;
for(int i = 0; i < myRecords.Count;i++)
{
string time = myRecords[i].ResponseTime;
label.Frame = new CoreGraphics.CGRect(45,TextLabel.Frame.Height + i *(labelSize + spacing),ContentView.Frame.Width,19);
label.Font = UIFont.FromName ("HelveticaNeueLTStd-ThCn", 18f);
label.TextColor = UIColor.DarkGray;
label.Text = string.Format("- {0}, {1}",otherInfo[i],time);
ContentView.AddSubview(label);
}
}
}catch(Exception ex)
{
Console.WriteLine (ex.Message + ex.StackTrace);
}
}

UITableView with SearchView makes new cells overlap old ones on search

Iam implementing a SearchView to filter the data in my UITableView. Iam able to search successfully, the only issue is when the UITableView data gets filtered, the old cells still exist and the filtered ones overlap them giving me a messy output. I have cleared the Table source as suggested by my answers on SO, but still not resolved the problem.
Here is what Iam trying to do:
FilterController
void searchFiler_TextChanged(object sender, UISearchBarTextChangedEventArgs e)
{
if (!string.IsNullOrEmpty(e.SearchText))
{
ppTable.Source = null;
AppDelegate.filteredList = null;
ppTable.ReloadData();
filteredModelList = filter(dupes, e.SearchText);
mAdapter = new PeoplePlacesSource(filteredModelList, "");
ppTable.Source = mAdapter;
ppTable.ReloadData();
}
else
{
ppTable.Source = null;
mAdapter = new PeoplePlacesSource(dupes, "");
searchFiler.TextChanged += searchFiler_TextChanged;
mAdapter.TableRowSelected += mAdapter_TableRowSelected;
ppTable.Source = mAdapter;
ppTable.ReloadData();
}
}
PeoplePlacesSource
public override UITableViewCell GetCell(UITableView tableView, Foundation.NSIndexPath indexPath)
{
cell = tableView.DequeueReusableCell("PeoplePlacesCell_Cell") as PeoplePlacesCell ?? PeoplePlacesCell.Create();
subList = userList.ElementAt(indexPath.Row);
cell.UpdatePeoplePlacesCell(subList);
return cell;
}
PeoplePlacesCell
internal void UpdatePeoplePlacesCell(System.Linq.IGrouping<string, Models.EmployeeModel> subList)
{
var yPosition =15;
var xPosition = 10;
var imgDefault = new UIImageView();
imgDefault.Frame = new CoreGraphics.CGRect(10, viewParent.Frame.Y, 60,60);
imgDefault.Image = UIImage.FromFile("ic_appicon.png");
CALayer profileImageCircle = imgDefault.Layer;
profileImageCircle.CornerRadius = 28;
profileImageCircle.BorderWidth = 2;
profileImageCircle.BorderColor = new CoreGraphics.CGColor(211, 34, 41);
profileImageCircle.MasksToBounds = true;
imgDefault.ClipsToBounds = true;
viewParent.AddSubview(imgDefault);
var labelUserName = new UILabel();
labelUserName.Frame = new CoreGraphics.CGRect(0, 0, viewContainer.Frame.Width, 30);
labelUserName.TextColor = UIColor.FromRGB(211, 34, 41);
labelUserName.Text = subList.Key ;
labelUserName.ClipsToBounds = true;
labelUserName.Font = UIFont.BoldSystemFontOfSize(17);
viewContainer.AddSubview(labelUserName);
var mList = subList.Take(5);
foreach (var employeeModel in mList)
{
var labelPlace = new UILabel();
labelPlace.Frame = new CoreGraphics.CGRect(0, yPosition, viewContainer.Frame.Width, 50);
if (employeeModel.Place.Contains(","))
{
labelPlace.Text = employeeModel.Place.Substring(0, employeeModel.Place.IndexOf(","));
}
else
{
labelPlace.Text = employeeModel.Place;
}
labelPlace.Font = UIFont.FromName(labelPlace.Font.Name, 12f);
labelUserName.SizeToFit();
labelPlace.ClipsToBounds = true;
viewContainer.AddSubview(labelPlace);
yPosition += 15;
}
}
How can I solve this? Any help is appreciated
Do you have the same problem after scroll? You cells are reused, but I don't see code for removing added subviews. Try to remove all subviews you added, before reusing cells.

Animate a layout constraint constant from one value to another using Xamarin.ios

I am using Xamarin studio and developing an iPad app with Xamarin.iOS.
I am setting a constant value against a layout constraint outlet in my c# file.
What I have at the moment (no animations)
_myRightSpaceConstraint.Constant = 50;
What I want
Animate this constant so that it goes from:
_myRightSpaceConstraint.Constant = 300;
to
_myRightSpaceConstraint.Constant = 50;
OR, similar to above but don't specifiy what the start constant is (300), instead I just take whatever it is set to in the xib file and animate to 50.
Is this possible to do this in Xamarin and if so are there any code examples to help me?
What I have tried - which doesnt work
UIView.BeginAnimations ("slideAnimation");
float _pt;
_pt = _myRightSpaceConstraint.Constant;
UIView.SetAnimationDuration (5);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myRightSpaceConstraint.Constant = 50;
UIView.CommitAnimations ();
This actually sets the constant successfully to 50 but with no animation.
Edit/Update:
I managed to achieve what I wanted with the following:
_myRightSpaceConstraint.Constant = 150;
_myViewWithTheConstraint.SetNeedsUpdateConstraints ();
UIView.BeginAnimations ("slideAnimation");
UIView.SetAnimationDuration (1);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myViewWithTheConstraint.LayoutIfNeeded ();
UIView.CommitAnimations ();
The following line was the key:
_myViewWithTheConstraint.LayoutIfNeeded ();
Call LayoutIfNeeded() on the constrained views, as part of the animations action of UIView.Animate:
NSLayoutConstraint[] dynConstraints;
UIView redView;
UIView greenView;
public ContentView()
{
BackgroundColor = UIColor.Blue;
redView = new UIView() {
BackgroundColor = UIColor.Red,
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(redView);
greenView = new UIView(){
BackgroundColor = UIColor.Green,
TranslatesAutoresizingMaskIntoConstraints = false
};
AddSubview(greenView);
var viewsDictionary = new NSMutableDictionary();
viewsDictionary["red"] = redView;
viewsDictionary["green"] = greenView;
dynConstraints= NSLayoutConstraint.FromVisualFormat("V:|-[red]-100-[green(==red)]-|", 0, new NSDictionary(), viewsDictionary);
AddConstraints(dynConstraints);
AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|-[red]-|", 0, new NSDictionary(), viewsDictionary));
AddConstraints(NSLayoutConstraint.FromVisualFormat("H:|-[green(==red)]", 0, new NSDictionary(), viewsDictionary));
this.UserInteractionEnabled = true;
}
public override void TouchesBegan(NSSet touches, UIEvent evt)
{
foreach(var constraint in dynConstraints)
{
constraint.Constant = 50;
}
UIView.Animate(0.5, () => {
redView.LayoutIfNeeded();
greenView.LayoutIfNeeded();
});
}
I managed to achieve what I wanted with the following:
_myRightSpaceConstraint.Constant = 150;
_myViewWithTheConstraint.SetNeedsUpdateConstraints ();
UIView.BeginAnimations ("slideAnimation");
UIView.SetAnimationDuration (1);
UIView.SetAnimationCurve (UIViewAnimationCurve.EaseInOut);
UIView.SetAnimationDelegate (this);
UIView.SetAnimationDidStopSelector (
new Selector ("slideAnimationFinished:"));
_myViewWithTheConstraint.LayoutIfNeeded ();
UIView.CommitAnimations ();
The following line was the key:
_myViewWithTheConstraint.LayoutIfNeeded ();

Setting the z-index of loader class

I'm working in Flash AS3, AIR 3.2 for iOS SDK. I'm loading in an image, then applying a shape and textfield over this. But it seems that z-index goes weird with the loader class. At the moment, when this is run, the text and shape is applied first, and the image then gets applied on top of these even though the methods are in a different order. How do I set the shape and text to be above an image that's loaded in from the loader class?
The methods in the main method:
displayImage();
overlayBox();
textAnimation();
These are the methods:
public function displayImage():void {
var imageurl:String = "image.jpg";
myLoader = new Loader();
var fileRequest:URLRequest = new URLRequest(imageurl);
myLoader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoaderProgress);
myLoader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoaderComplete);
myLoader.load(fileRequest);
}
public function onLoaderProgress(e:ProgressEvent) {
trace(e.bytesLoaded, e.bytesTotal); // this is where progress will be monitored
}
public function onLoaderComplete(e:Event) {
image = new Bitmap(e.target.content.bitmapData);
var imageWidth:Number = image.width;
var imageHeight:Number = image.height;
var resizeWidthVar:Number;
var resizeHeightVar:Number;
trace("Image width: " + image.width);
trace("Image height: " + image.height);
if(imageWidth >= imageHeight) {
resizeHeightVar = imageHeight/displayRes;
trace("resizeHeightVar = " + resizeHeightVar);
imageWidth = imageWidth/resizeHeightVar;
imageHeight = imageHeight/resizeHeightVar;
}
else {
resizeWidthVar = imageWidth/displayRes;
trace("resizeWidthVar = " + resizeWidthVar);
imageWidth = imageWidth/resizeWidthVar;
imageHeight = imageHeight/resizeWidthVar;
}
image.width = imageWidth;
image.height = imageHeight;
trace("Image width: " + image.width);
trace("Image height: " + image.height);
image.x = xScreenPos;
image.y = yScreenPos;
addChild(image); // the image is now loaded, so let's add it to the display tree!
}
public function overlayBox():void {
var overlaySquare:Sprite = new Sprite();
addChild(overlaySquare);
overlaySquare.graphics.beginFill(0x00000, 0.7);
overlaySquare.graphics.drawRect(0, 0, displayRes, displayRes);
overlaySquare.graphics.endFill();
overlaySquare.x = xScreenPos;
overlaySquare.y = yScreenPos;
}
public function textAnimation():void {
//set text format
textFormat.font = "Helvetica Neue Light";
textFormat.size = 12;
textFormat.bold = false;
textFormat.color = 0x000000;
// pass text format
textOne.defaultTextFormat = textFormat;
textOne.text = "Blah blah blah blah";
textOne.autoSize = TextFieldAutoSize.LEFT;
textOne.x = xScreenPos;
textOne.y = yScreenPos;
//add to stage
addChild(textOne);
}
One of the solutions is to replace addChild(image); with the addChildAt(image, 0); another one is to add loader addChild(loader); and don't add image in the complete handler.

Resources