Custom UISlider using UIEdgedInset does not render well - ios

I'm trying to do a custom uislider using images (without a visible knob, i hide it when user can't edit and show it when he can) The problem is that the the side render perfectly but the right part is cute and doesn't seems to use the edges...
Any idea how i can edit it ?
Actual code :
let capLeft:CGFloat = 9
let capRight:CGFloat = 9
imageMin = imageMinimum?.resizableImage(withCapInsets: UIEdgeInsets(top: 0, left: capLeft, bottom: 0, right: capRight), resizingMode: .stretch)
imageMax = imageMaximum
slider.setMaximumTrackImage(imageMax, for: UIControlState())
slider.setMinimumTrackImage(imageMin, for: UIControlState())
How it's rendering :
How it should render :
Minimum track image :
Maximum Tracking Image :
Do you have any idea ?

I think there is a bit of confusion about Min and Max images with UISlider.
The Min image is drawn (and stretched) on the Left side of the Thumb. The Max image is drawn (and stretched) on the Right side of the Thumb.
Create a small, square solid red image - such as 16x16 - and assign it (without insets) to .setMaximumTrackImage. See how that ends up looking, as you go from low to high values.
Edit: I used NO insets on the Min image for this example...
Note: I used a 20x20 clear image for the Thumb in these caps.

Related

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

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.

How to create a limit for the UILabel in swift

I want to explain my question with codes. First you can see the custom label codes in the below;
let resultLabel : UILabel = {
let lbl = UILabel()
lbl.textColor = .white
lbl.textAlignment = .right
lbl.text = "0"
lbl.font = UIFont(name: "Helvetica Neue", size: 35)
lbl.minimumScaleFactor = 0.75
lbl.lineBreakMode = .byClipping
lbl.adjustsFontSizeToFitWidth = true
return lbl
}()
I just created label with these lines of codes. I also give them specific height according to view's frame height size and padding left and the right you'll see the constraint codes in the below.
resultLabel.anchor(top: view.topAnchor, left: view.leftAnchor, bottom: nil, right: view.rightAnchor, paddingTop: view.frame.size.height / 7, paddingLeft: 2, paddingBottom: 0, paddingRight: 5, width: 0, height: view.frame.size.height / 7)
I'll assign value into UILabel according to clicking button so i want to set chracter limit for the UILabel. According to code that i written it cropped data as i wanted but it didn't do that same action in the value. How can achieve of that could you help me out? Thanks.
What you want is not possible out of the box, and would be really strange in my opinion. Now the data and its presentation are separated, as they should be. Imagine, if your view controller size changed (the device got rotated, or your app is run on iPad in split mode, and the user resized the apps) - then you would be able to see more of your data. Because the label keeps the original data, everything would happen automatically. If it cropped the data to match its rendered representation, you would need to react to all such changes and reassign the original data to the label.
To provide a real world example - imagine you are looking at a huge (building sized) billboard, through a small (lets size, letter paper sized) window. You can see only a portion of the billboard, but everything is still there. In the same way, a UILabel is just a "window" onto the data provided.
Now, implementing this won't be trivial. Such a UIQuantumLabel* would need to take into consideration the width of each letter/digit/emoji/character in the data for current font at its current size (unless you were to limit it to monospaced fonts), take into consideration whether the automatic font scaling has happened and at what magnitude, whether the user has decreased/increased the font size in devices accessibility settings, and probably some more factors.
What is your use case for this? Why would you want to crop your data, and not keep the original?
*UIQuantumLabel because it reminded me of quantum mechanics (at least what I remember of it), where observing an object changes it state :)

UISegmentedControl maintain aspect ratio on image

I'm having a hard time making images on a UISegmentedControl keep their aspect ratio and not scale to all sides.
Here's what it looks like:
The images are 100X100(except nr 6 gonna replace soon) and I want them to maintain the aspect ratio.
I have tried:
self.segment.contentMode = .ScaleAspectFit
//and:
self.segment.contentMode = UIViewContentMode.Center
Are there a way I can target the UIImageView in the segment..that way I can set the contentMode..right? Or is there another approach?
Thanks
segmentedControl.subviews.flatMap{$0.subviews}.forEach { subview in
if let imageView = subview as? UIImageView, let image = imageView.image, image.size.width > 5 {
// The imageView which isn't separator
imageView.contentMode = .scaleAspectFit
}
}
Actually, there's a great, general purpose solution for this:
UIImageView.appearance(whenContainedInInstancesOf: [UISegmentedControl.self]).contentMode = .scaleAspectFit
This uses the approach described here: UIImageView.appearance is overriding UISegmentedControl.appearance
In my case, I constrained it to a subclass of UISegmentedControl (in case I want the default aspectFill for other situations).
I didn't find how to set the contentMode to ScaleAspectFit but you can use the following code to set a margin around your image when you are setting the image :
yourSegmentedControl.setImage(yourImage.resizableImage(withCapInsets: .init(top: 0, left: 10, bottom: 0, right: 10), resizingMode: .stretch), forSegmentAt: 0)
You can change the values of "top", "left", "bottom" and "right" as you want.
This worked for me, I hope it will help!
It is probably late for this, but Im sure it will help someone.
My Problem #1:
Images in the segmented control are distorted in ratio.
My Problem #2:
You can't even change the colour of the image. It remains black. Even if you use .alwaysTemplate and imageview tint colour. It wont budge.
Solution:
Forget trying to hack the SDK, or achieving the goal through unofficial means. Apple can easily change the SegmentedControl and all your work becomes redundant.
Use this instead: BetterSegmentedControl. Happy coding.
It is highly customisable and easy to use, plus it supports images.

UISlider MaximumTrackImage clips when slider has extreme max values

I've dragged a UISlider to my view using Xcode's storyboard. Then I made an outlet and customised slider's appearance (in Swift) as follows:
slider.setMinimumTrackImage(UIImage(named: "Images/slider_min.png")?.stretchableImageWithLeftCapWidth(3, topCapHeight: 0), forState: UIControlState.Normal)
slider.setMaximumTrackImage(UIImage(named: "Images/slider_max.png")?.stretchableImageWithLeftCapWidth(3, topCapHeight: 0), forState: UIControlState.Normal)
slider.setThumbImage(UIImage(named: "Images/slider_thumb.png"), forState: UIControlState.Normal)
slider.setThumbImage(UIImage(named: "Images/slider_thumb.png"), forState: UIControlState.Highlighted)
The slider is stepped so possible values are integers ∈ [1,12].
These are the referenced images, they are transparent PNGs:
I'm having problems with the two biggest possible values (11, 12): the MaximumTrackImage clips for some reason. This is what happens:
Initial, minimum position, value = 1
Last OK position, value = 10
First position where the clipping occurs, value = 11
Maximum position, still clipping, value = 12
Why this happens? Can this be fixed or are there any workarounds?
Oh well, it seems the problem was with the MaximumTrackImage—it was unnecessarily wide. I cropped the track images to be 6 px in width and the problem disappeared.
Cropping the MaximumTrackImage was sufficient, but cropping the MinimumTrackImage too didn't hurt.

How to programmatically create a UISlider like that of Apple Music in Swift

I'm looking to create a UISlider like the one below:
I've seen code like the following to change the image, but ideally I'd like to forgo using an image and create a basic downward line programmatically.
var thumbImage : UIImage = UIImage(named: "yourImage")!
var size = CGSizeMake( thumbImage.size.width * ratio, thumbImage.size.height * ratio )
self.setThumbImage( self.imageWithImage(thumbImage, scaledToSize: size), forState: UIControlState.Normal )
A UISlider is designed to use an image for the "thumb" control. If you want to draw the thumb control programmatically you will need to create your own control. A slider isn't that complicated. It would be fairly straightforward. (But it would be a heck of a lot easier to just use the standard slider control with a red line as the thumb image.)

Resources