How can I set one subview below another subview in xamarin iOS - ios

var mainStack = new UIStackView();
mainStack.Alignment = UIStackViewAlignment.Leading;
mainStack.Spacing = 10;
mainStack.Axis = UILayoutConstraintAxis.Vertical;
mainStack.Frame = new CGRect(10,10,Frame.Width - 30,Frame.Height - 100);
var mainStack1 = new UIStackView();
mainStack1.Alignment = UIStackViewAlignment.Center;
mainStack1.Spacing = 10;
mainStack1.Axis = UILayoutConstraintAxis.Vertical;
mainStack1.Frame = new CGRect(5, 5, Frame.Width - 30, Frame.Height - 200);
this.AddSubview(mainStack);
this.AddSubview(mainStack1);
These are the two subviews i have used, I want to insert one subview below to another subview. I faced a problem that the two subviews are override.

The easiest thing is to change the order you add the views. The last one added will be on top, so if the issue is just with the exact code you shared, just reverse the order of adding the subviews:
this.AddSubview(mainStack1);
this.AddSubview(mainStack);
Also you can bring a subview to the front with (assuming this is a view):
this.BringSubviewToFront(mainStack);
Or you can adjust the Z-Order using the Layer property of a view:
mainStack1.Layer.ZPosition = 0;
mainStack.Layer.ZPosition = 1;
UIView.Layer with higher z positions will appear in front of UIView.Layer with lower z positions.

Related

Xamarin iOS add dynamic amount of Views to StackView

I am trying to add a dynamic amount of xib Views to a Stackpanel which is inside a UIView which is inside a UIScrollView.
Actually I am doing this completely with code...
// These 3 values are completely variable
private int viewHeight = 100;
private int stackviewSpacing = 8;
private int countViews = 7;
for (int i = 0; i < countViews; i++)
{
SessionViewItem sView = SessionViewItem.Create();
sView.Frame = new CoreGraphics.CGRect(0, i * viewHeight + i * stackviewSpacing, this.svSessions.Frame.Width, viewHeight);
svSessions.AddSubview(sView);
}
... but I think this could not be the best solution.
Question 1: Is there a better solution to add the Views to the Stackpanel?
Also I only can see the first 5 items because the UIScrollView does not resize to it's content size.
Question 2: What do I need to make the UIScrollView scrollable for the whole content?
Thanks a lot for your help!

How to create UIStackView from code correctly

I can't understand why this layout won't render the way i need it. Completing the requirement on android with linearlayouts should be equivalent to this?
What i get:
What i need:
My code:
// my stackview only renders at all if i pass any height > 0 && width > 0,
// but i would love this to be as small as possible, given that all children
// are rendered.
var stackView = new UIStackView(View.Frame);
stackView.Axis = UILayoutConstraintAxis.Vertical;
stackView.Distribution = UIStackViewDistribution.Fill;
foreach (var deviceVm in devices)
{
// i would prefer this not to have a rect parameter and scale as needed.
var descriptionLabel = new UILabel(new CGRect(0, 0, View.Bounds.Width, 20));
descriptionLabel.Text = deviceVm.Description;
descriptionLabel.TextColor = UIColor.Blue;
descriptionLabel.ContentMode = UIViewContentMode.ScaleToFill;
stackView.AddArrangedSubview(descriptionLabel);
}
// i assume this should make it as small as possible, as big as necessary?
stackView.SizeToFit();
var scrollView = new UIScrollView(View.Frame);
scrollView.BackgroundColor = UIColor.Yellow;
scrollView.AddSubview(stackView);
View.AddSubview(scrollView);
Can someone spot a mistake i am doing here? Am i configuring the StackView incorrectly or is this control not the equivalent of LinearLayout(android) / StackPanel(wpf) ?
PS: Sorry for eye cancer paint pictures.

Swift: Changing UIView frame but display doesn't update

I'm trying to dynamically resize the frame of a UIView. I can update the frame in the code and see that the values have changed, but the actual display never changes, even though I run setNeedsDisplay().
I'm following this post, where I define a new frame via CGRectMake, and then set the UIView's frame to this new frame. i.e., I'm doing this...
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
If I print out the value of the UIView's frame, I see that it's changing as I like. But the display (in the Simulator) never reflects these changes.
Any idea how to fix this?
Update: In greater detail: I'm trying to programmatically cover up one UIView with another. It's a horizontal "VU Meter", consisting of a base UIImageView showing a color gradient, that gets partially dynamically "covered" up by a UIView with a black background.
The UIImageView "VUBarImageView" is defined in StoryBoard and is subject to AutoLayout. The black UIView "VUBarCover" is defined purely programmatically, with no AutoLayout constraints.
Here's the relevant parts of the code for completeness... The trouble I'm having is in updateVUMeter()...
#IBOutlet weak var VUBarImageView: UIImageView!
var VUBarCover : UIView!
// this gets called after AutoLayout is finished
override func viewDidLayoutSubviews() {
// cover up VU Meter completely
let center = VUBarImageView.center
let width = VUBarImageView.frame.width
let height = VUBarImageView.frame.height
let frame = VUBarImageView.frame
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
VUBarCover.backgroundColor = UIColor.blueColor() // use black eventually. blue lets us see it for testing
}
// partially cover up VUBarImage with black VUBarCover coming from the "right"
func updateVUMeter(inputValue:Float) { //inputValue is in dB
//let val = pow(10.0,inputValue/10) // convert from dB
let val = Float( Double(arc4random())/Double(UInt32.max) ) //for Simulator testing, just use random numbers between 0 and 1
print("val = ",val)
let fullWidth = VUBarImageView.frame.width
let maxX = VUBarImageView.frame.maxX
let width = fullWidth * CGFloat(1.0-val)
let minX = maxX - width
let minY = VUBarImageView.frame.minY
let height = VUBarImageView.frame.height
let newFrame = CGRectMake(minX,minY, width, height)
VUBarCover.frame = newFrame
VUBarCover.setNeedsDisplay()
print("fullWidth = ",fullWidth,"width = ",width)
print(" newFrame = ",newFrame,"VUBarCover.frame = ",VUBarCover.frame)
}
And sample results are:
val = 0.9177
fullWidth = 285.0 width = 23.4556210041046
newFrame = (278.544378995895, 93.5, 23.4556210041046, 10.0) VUBarCover.frame = (278.544378995895, 93.5, 23.4556210041046, 10.0)
val = 0.878985
fullWidth = 285.0 width = 34.4891595840454
newFrame = (267.510840415955, 93.5, 34.4891595840454, 10.0) VUBarCover.frame = (267.510840415955, 93.5, 34.4891595840454, 10.0)
val = 0.955011
fullWidth = 285.0 width = 12.8218790888786
newFrame = (289.178120911121, 93.5, 12.8218790888786, 10.0) VUBarCover.frame = (289.178120911121, 93.5, 12.8218790888786, 10.0)
...i.e., we see that VUBarCover.frame is changing 'internally', but on the screen it never changes. What we see instead is the full-size cover, completely covering the image below (ca. 300 pixels wide), even though its width should be only, about 12 pixels).
Even if I do a setNeedsDisplay() on the superview of VUBarCover, nothing changes.
Help? Thanks.
First, you have a few errors worth noting:
Instance variables (like VUBarCover and MainView should always begin with a lowercase letter (like mainView).
You should call super.viewDidLayoutSubviews() at the beginning of your override implementation
Second, viewDidLayoutSubviews() can be called any number of times, so your implementation of this method should be idempotent, meaning it has an identical effect no matter how many times it's called. But when you call:
VUBarCover = UIView(frame: frame)
MainView.addSubview(VUBarCover)
You are creating a new UIView and adding it to the view hierarchy, along with the others you may have added in the past. So it looks like the frame isn't updating on the screen. In fact, you just can't tell because the old views are behind the one you're updating and they're not changing.
Instead, you probably want to create this once:
var vuBarCover = UIView()
Add it as a subview in viewDidLoad():
mainView.addSubview(vuBarCover)
And modify its frame in viewDidLayoutSubviews():
vuBarCover.frame = vuBarImageView.frame
You don't need to call setNeedsDisplay().
In my case, there were animations left on the layer, after removing them, the frame changes are updated:
myView.layer.removeAllAnimations()
iOS displays presentationLayer of a UIView on the screen, animations are played on that layer (frame updates goes there during animation).
I am making a custom UIView like you right now, maybe I can help.
Firstly, viewDidLayoutSubviews() like your comment: this gets called after AutoLayout is finished. And after every layout did set, you start to set new frame for your UIView and UIImage, maybe the bug is here. Please try to move your code in viewDidLayoutSubviews() to layoutSubviews(). And don't forget add super.layoutSubviews() in override function, which can help you away from hundreds of bugs :].
Secondly, only if you override the drawRect: method, then you should call setNeedsDisplay(), which is telling system that i need to redraw my view, and system will call drawRect: method appropriately.
Hope you can figure it out.

How to create a variable number of UIImageViews in swift

My problem is that based on the number of groups a person has I want to dynamically create that many UIImageView and assign them to the view. I know how to create a single UIImageView and put it onto the view but how can I create a variable number of them since creating another with the same name seems to just overwrite the original? I tried sending the UIImageView into an Array but got an optional error.
circleView = UIImageView(frame:CGRectMake(125, y, 75, 75))
y+=150
circleView.image = UIImage(named:"circle.png")
circleView.tag = i
self.view.addSubview(circleView)
circleArray[i] = circleView
The problem is that you keep reusing the same circleView instance. When you add it to the array, you are just adding a reference to it. You then reinitialize it, which wipes it out. I also don't see where you are incrementing i. Try something like this:
var circleArray = Array<UIImageView>()
var y : CGFloat = 0.0
var i = 0
circleArray.append(UIImageView(frame:CGRectMake(125, y, 75, 75)))
var circleView = circleArray[i]
circleView.image = UIImage(named:"circle.png")
circleView.tag = i
self.view.addSubview(circleView)
y+=150
i += 1
You need to use circleArray.append(circleView)

Easier/correct way to resize elements according to screen size

I've got an iOS app thats for all devices. I've designed it perfectly for the iPad but now I'm struggling a bit on resizing elements for smaller screens. My datagrids scale and move perfectly but when it comes to buttons, they just get warped and messed up. The down states on the buttons are massive and stretched and different to the up states. My logic tells me that if I scale the button, it should scale the up and down states accordingly as if you were just resizing on the stage. I'm just trying to make the buttons slightly bigger and move them over a bit..
if (Capabilities.screenResolutionX < 700) {
dg.move(120, 150);
dg.width = 1120;
dgPlace.move(70, 20);
dgPlace.width = 260;
dgPlace.height = 650;
dgPlace.rowCount = 21;
dgPlace.setRendererStyle("textFormat", myTextFormat3);
dgPlace.setStyle("headerTextFormat", myTextFormat3);
btnPlacesEditAdd.width = btnPlacesEditAdd.width+20;
btnPlacesEditAdd.height = btnPlacesEditAdd.height+20;
btnPlacesEditRemove.width = btnPlacesEditAdd.width+20;
btnPlacesEditRemove.height = btnPlacesEditAdd.height+20;
btnPlacesEditSet.width = btnPlacesEditAdd.width+20;
btnPlacesEditSet.height = btnPlacesEditAdd.height+20;
btnPlacesEditAdd.x = btnPlacesEditAdd.x+20;
btnPlacesEditAdd.y = btnPlacesEditAdd.y+20;
btnPlacesEditSet.x = btnPlacesEditSet.x+20;
btnPlacesEditSet.y = btnPlacesEditSet.y+20;
btnPlacesEditRemove.x = btnPlacesEditRemove.x+20;
btnPlacesEditRemove.y = btnPlacesEditRemove.y+20;
}

Resources