Xamarin - Button with text and image in absolute layout results in mis-aligned elements - ios

I am trying to create a button in a Xamarin Forms cross-platform app (iOS and Android), where the button has both text and an image. The XAML is pretty straightforward:
<AbsoluteLayout ...>
<Labels and backgrounds and such>
<Button x:Name="HomeButton2" TranslationX="6" TranslationY="100"
BackgroundColor="#efeff4" TextColor="#4a4a4a"
WidthRequest="58" HeightRequest="76"
ContentLayout="Top,5"
Image="TaskBar_Assets_HomeButtonIcon.png" Text="Home"
Clicked="HomeButton_Clicked" />
</AbsoluteLayout>
but what I get on the iPad is a button where both the image and the text are strangely pushed over to the side:
(the source image "TaskBar_Assets_HomeButtonIcon.png" is 47 x 44 so it should fit fine in the overall button area)
The only way I can find to make this look better, is to make a custom control based on Button, and then I can see that several of the properties of the underlying UIButton seem wonky:
The Control.ImageView.Frame is all zeroes:
Control.ImageView = <UIImageView: 0x12df52940; frame = (0 0; 0 0);
clipsToBounds = YES; opaque = NO; userInteractionEnabled = NO;
layer = <CALayer: 0x173623180>>
The Control.ImageEdgeInsets and .TitleEdgeInsets look odd (the right + left seem like they leave no space for the image or text):
Control.ImageEdgeInsets = {-8.9501953125, 20.33935546875, 8.9501953125, -20.33935546875}
Control.TitleEdgeInsets = {22, -23.5, -22, 23.5}
What I'm doing, is adjusting the Control.ImageEdgeInsets so that Control.ImageEdgeInsets.Left is equal to the half of the (button width minus the image width) and setting Control.ImageEdgeInsets.Right to zero (for no particular reason except that it works)
and then figuring out what to set Control.TitleEdgeInsets was done with trial & error, I ended up with values related to the width of the "Home" text (41 pixels):
Control.ImageEdgeInsets updated to {-8.9501953125, 5.5, 8.9501953125, 0}
Control.TitleEdgeInsets updated to {22, -50, -22, -9}
That results in a reasonable button look:
although it looks like I need to do more trial & error to get the text "Home" actually centered.
But why do I need to go through all this? Why doesn't the button just display text & image correctly in the first place?
And if I do have to go through all this, why are the values for Left & Right for ImageEdgeInsets and TitleEdgeInsets so different?

Most of the articles I have read about images on buttons suggest constructing your own using an Image and a Label in a grid using a gesture recognizer to handle the tap.
You could also try a button and an image in a grid.
Use Margin to adjust placement.
I try and stay clear of absolute layout.

Here's the ButtonRenderer source code from Xamarin.Froms.If you set the ContentLayout to Top, the below codes will be run:
void ComputeEdgeInsets(UIButton button, Button.ButtonContentLayout layout)
{
...
var horizontalImageOffset = labelWidth / 2;
var horizontalTitleOffset = imageWidth / 2;
...
button.ImageEdgeInsets = new UIEdgeInsets(-imageVertOffset, horizontalImageOffset, imageVertOffset, -horizontalImageOffset);
button.TitleEdgeInsets = new UIEdgeInsets(titleVertOffset, -horizontalTitleOffset, -titleVertOffset, horizontalTitleOffset);
}
As the codes show, the Left offset of image is horizontalImageOffset which is labelWidth / 2. The Left offset of title is horizontalTitleOffset which is imageWidth / 2.
So, when the text is wider, the left offset of image will be bigger. When the image is wider, the left offset of text will be bigger.
Edit:
In native iOS, the default layout is like the left image: Image is at left and Label is at right. In Xamarin for Top setting, Xamarin moves the Image up and right, moves the Label down and left to makes them like the right image. I paint this illustration, hope it clear.

Related

Swift 4 - Editing label frame.size.height with negative number

So I have a label that I've made in Xcode's storyboard which I want to later edit in my code. I want it to simulate something like a vertical bar so I am editing its height by doing:
answerE.frame.size.height = -200
The problem comes from the negative number, I want the label to "grow" up so the height has to be negative from its original position... I have the line in code in a simple action on button press, but each time the line is executed the label moves "up" and eventually after 3-4 clicks is out of the screen.
I just want to edit its height, what is the correct way and what am I doing wrong?
My exact line in code is:
label.frame.size.height = -CGFloat(Double(x)/Double(y) * (200))
If you have added the label in storyboard, why not you use constraints to get the result.
Add leading, trailing , bottom and fixed height constraint and connect IBOutlet to height constraint. Change the constant value of height constraint at the event which you want to perform.
If I'm right, you want the label to gain height, keeping the same bottom edge, but the top edge moving up.
In order to do this, you want to change the frame.origin.y as you change the frame.size.height at the same amount, as its placement (and so top edge) is determined by its origin. So maybe make it zero height, place it where you want it in storyboard, and then when you want it to 'grow' by x:
label.frame.size.height = label.frame.height + x
label.frame.origin.y = label.frame.origin.y - x

How to limit iOS button title with 0 lines in background area?

As above picture, the blue area is the button, but the title with 0 lines is out of the area, also I tried that set the titleLabel frame with the frame with the button, but still it does not work, so any tips here??
Clip the content to bounds:
myButton.clipsToBounds = true
may be this will help:
1) add a button
2) set line break (see screen)
3) set multimple lines in text (use alt+enter to new line )
4) Set constraints for leading and for top - so width and height can be calculated by autolayout
5) set background color if you need

How to create a UiTableView of balloons like iOS widgets - Swift 3/Xcode 8

I want to create a list of events in my application and I think this would be a perfect look, but I have no idea how to do it. Can anybody help me?
Thanks!!
Check out the following method
1) in the interface builder drag a new UITableViewCell
2) Set the contentView and background of tableview to UIColor.clear / UIColor.clearColor();
2) dragIn a view and adjust the size as per requirement
(This will act as container View i.e the bigger balloon)
3) now select background colour to white and change opacity to 85 - 90 %
this will give you the desired color
4) Add Label o top and select the same background colour and the opacity as 50 % as main view and as there is a difference in opacity of 2 containers you will get the desired effect
5) Connect an outlet connection of the mainView and Label
6) set corner radius to view and and label
self.mainView.layer.cornerRadius = 10; // or anything as per requirement
AND
self.label.layer.cornerRadius = 10; // run it now to adjust the corner radius

UIslider and UI progress view embedded

I'm trying to build a slider embedded in a progress bar, so that slider's minimum image settles with the progress bar 'progress image' and the user can slide only inside the 'progress track image'.
Something like image below:
As in the image,
green section is a progress view
section right to the red (minimum slider value image) is a slider &
should dynamically adjust to the 'progress image' and should hide the
'progress track'
I hav tried to set the
minimumvalueimage
of slider programatically as below:
override func trackRectForBounds(bounds: CGRect) -> CGRect {
// keeps original origin and width, changes height, you get the idea
let customBounds = CGRectMake(7, 0, 180, 15)
super.trackRectForBounds(customBounds)
return customBounds
}
Is this a correct way to do this task, please suggest me something. I'm stuck here, and not in the right track..
if I'm not clear about anything please let me know...Any process are appreciated as long as within swift.
I was stuck because of the logic to implement this. Finally I got an way to set the progress bar and slider with the percentage i.e multiplier.
Firstly, I set the progress bar to 100%,
Then, I set the multiplier, which will set the percentage of progress-bar UI limit and set it to its position right next to the
slider.
And finally, The red icon is minimum value image for slider which sticks to the progress-bar trailing margin, (programmatically constraints).
Or, via Storyboard You could just position it to the view in-between first(i.e. ProgressView) and second(i.e. SliderView) view.
So, the UISlider will get its position from 100% of the view width - % covered by the progress-bar
EDIT: - I may provide the code sample, if required.. just let me know. :)
Happy Coding: )

Swift: programmatically align labels for different IOS screen sizes

I'm new to Swift and ios development. I have 6 labels and a horizontal SKScene in my App. I would like to align those 6 labels beautifully and automatically. Now I have fixed the positions and the alignment always looks awful on some screen size while good on other.
I have not used storyboards or other graphical editors for building the ui but everything is done in code. Therefore I'm looking for a programmatic solution (code examples) for handling the alignment.
If you want to place them in the middle of the screen horizontally, but give them different y positions, you could just do something like this for each label:
label.position = CGPointMake(CGRectGetMidX(self.frame),CGRectGetMaxY(self.frame) * 0.80)
To place them at different y positions, just multiply by the maxY by a different decimal number. This way, all of the labels are aligned along the x-axis and appear at different y-positions, like a column and they will appear this way on every screen size because they are positioned relative to the screen size and not in a fixed position.
You can align the labels (lets say at the center of the screen) like this.
var label1 = UILabel(CGRectMake: 0, 0, 200, 40)
label1.center = CGPointMake(UIScreen.mainScreen().bounds.size.width/2, 30)
var label2 = UILabel(CGRectMake: 0, 0, 200, 40)
label2.center = CGPointMake(UIScreen.mainScreen().bounds.size.width/2, label1.center.y + 30)
and so on. Just reference the main screen bounds and not static points for alignment, so that they are centered in any screen size.
What I ended up doing was to create an empty SKSprite to which I included the SKLabels. Now I can control by the pixed the distances between labels but align the top-level sprite in the middle of the screen despite screen size.

Resources