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!
Related
I have tried to use some the existing solution for iOS keyboard avoiding but none of the existing solutions seems to be working properly with some of my rather complicated views and I am now having to implement my own system. Thus far I have managed to come up with the following which works quite good:
_keyboardDidShow(e) {
const keyboardHeight = e.endCoordinates.height;
const windowHeight = Dimensions.get('window').height;
const keyboardTop = windowHeight - keyboardHeight;
const margin = 10;
const currentlyFocusedField = TextInput.State.currentlyFocusedField();
UIManager.measureInWindow(currentlyFocusedField, (x, y, width, height) => {
const fieldBottom = y + height;
const offset = fieldBottom - keyboardTop + 10;
if (offset > 0) {
this.setState({ offsetY: -1 * offset, offsettingKeyboard: true });
}
});
}
I should mention that these inputs are inside ScrollViews which are themselves in a bunch of other stuff.
The problem is that when the handler is called for a TextInput that has not been scrolled up inside its view, the proper "fieldBottom" position is obtained without adding the height while the height addition is needed for the real position of a field inside a view that has been scrolled.
I cannot decide if this is a bug or if I am missing something. Is there perhaps a way I can check if the input's parent has been scrolled?
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.
How to find the maximum possible number of items could be placed in a UICollectionViewrow?
In the following example which is 3.
Apple's UICollectionViewFlowLayout doesn't "know" the max number of items it can display on the screen. It basically just calculates the coordinates of the next cell to place it next to the previous one and verifies if it fits in the screen on the fly. If it doesn't, it will recalculate new coordinates to place the cell as first element of the next line/column (depending on the orientation).
You could do the same with a formula. Something like this maybe :
int verticalCount = (int)((self.collectionViewContentSize.width - self.minimumInteritemSpacing)/(self.itemSize.width + self.minimumInteritemSpacing));
int horizontalCount = (int)((self.collectionViewContentSize.height - self.minimumLineSpacing)/(self.itemSize.height + self.minimumLineSpacing));
use this fomula
int noOfCell = (self.view.frame.size.width - leftPadding - rightPadding)/(cell.frame.size.width + spacebetweenCells);
After considering the answer form #Kujey and with a slide change I could find the solution as follows.
func maximumNumberOfCellsInARow() -> Int {
let collectionViewFlowLayout = collectionView.collectionViewLayout as! UICollectionViewFlowLayout
return Int((collectionView.contentSize.width - collectionViewFlowLayout.minimumInteritemSpacing)/(collectionViewFlowLayout.itemSize.width + collectionViewFlowLayout.minimumInteritemSpacing))
}
#Kujey, sorry I could not mark your answer as a right answer even though my answer is driven from yours, because it needs a significant change.
I have created this formula, you can complicate it including section insets and other params.
-(NSInteger)collectionView:(UICollectionView *)collectionView numberOfItemsInSection:(NSInteger)section {
NSUInteger totalItems = X;
UICollectionViewFlowLayout* collectionViewLayout = (UICollectionViewFlowLayout *)collectionView.collectionViewLayout;
NSLog(#"MAX WIDTH: %li",(long) collectionView.frame.size.width);
NSUInteger maxVisibleItems = (collectionView.frame.size.width + collectionViewLayout.minimumInteritemSpacing) / (collectionViewLayout.itemSize.width + collectionViewLayout.minimumInteritemSpacing);
NSLog(#"MAX VISIBLE ITEMS: %li",(long) maxVisibleItems);
if (totalItems < maxVisibleItems ) {
return totalItems;
}else{
return maxVisibleItems;
}
}
I have a view containing a scrollview the size of a large image, and i'd like to add a position indicator for where you are in the scrollview, like a map in games.
I've created a smaller view on top of the scrollview with a smaller version of the image, and I'm wondering how I could add a rectangle relative to the size and position of the zoom scale of the scrollview in my smaller view, to indicate on the small image what part of the larger image you're currently looking at? I'm targeting iOS 5+ using ARC.
here's what i have so far - it seems to set the origin correctly, but when i zoom it gets smaller when it should get bigger and vice versa:
int scrollxint = self.scrollView.bounds.origin.x;
int scrollyint = self.scrollView.bounds.origin.y;
int scrollxlength = self.scrollView.contentSize.width;
int scrollylength = self.scrollView.contentSize.height;
int reducedscrollxint = (scrollxint*0.05);
int reducedscrollyint = (scrollyint*0.05);
int reducedscrollxlength = (scrollxlength*0.05);
int reducedscrollylength = (scrollylength*0.05);
areaFrame.frame = CGRectMake(reducedscrollxint, reducedscrollyint, reducedscrollxlength, reducedscrollylength);
[self.mapView addSubview:areaFrame];
Any help would be much appreciated.
I had to use the zoom scale relative to the original size of the area indicator to make this work, but this code is working for me:
int scrollxint = self.scrollView.bounds.origin.x;
int scrollyint = self.scrollView.bounds.origin.y;
float scale = self.scrollView.zoomScale;
int reducedscrollxint = (scrollxint*0.05);
int reducedscrollyint = (scrollyint*0.05);
areaFrame.frame = CGRectMake(reducedscrollxint, reducedscrollyint, (10/scale), (6.5/scale));
[self.mapView addSubview:areaFrame];
I have HorizontalFieldManager,VerticalFieldManager and LabelField. LabelField placed in HorizontalFieldManager and multiple HorizontalFieldManager are placed in VerticalFieldManager.
When i try to get LabelField height using labelfield.getHeight(); it returns 0 . if there are multiple line in Labelfield, it also give me height returns 0. same issue i m facing for HorizontalFieldManager .
After getting there height i want to calculate VerticalFieldManager height and set height dynamically for the screen.
How can i calculate the height of Label or Horizontalfieldmanager?
Use labelField.getPreferredHeight() and manager.getPreferredHeight() not labelField.getHeight()
This should work for you
The method Farid suggests it's a bit difficult to use, because you will need labelWidth.
For multiline label this labelWidth may not be the same as parent managers available width, or some exact width you had set, because each line can have different width depending on if words did fit maxWidth or didn't.
NOTE: as Nate pointed out in comments, it's a good idea to also add advance for spaces.
I modified the code to include that.
Here is the method I use to overcome these problems:
public int getPreferredHeight() {
String text = getText();
int maxWidth = getManager().getPreferredWidth();
int spaceAdvance = getFont().getAdvance(' ');
String[] words = StringUtilities.stringToWords(text);
int lastWordAdvance = 0;
int lines = 1;
for (int i = 0; i < words.length; i++) {
int wordAdvance = getFont().getAdvance(words[i]) + spaceAdvance;
if (lastWordAdvance + wordAdvance < maxWidth ) {
lastWordAdvance += wordAdvance;
} else {
lines++;
lastWordAdvance = wordAdvance;
}
}
return (int)lines * getFont().getHeight();
}
If you can leave the decision about the size of the LabelField until after it has been laid out, then you will get it accurately from getHeight(). This means you can actually get the correct result, including factoring in any margin or padding for the LabelField, that I think
int maxWidth = getManager().getPreferredWidth();
will miss.
Initially this seems quite difficult, because typically it is good to know the height when you add the Field to the screen. But the general principle is that you should do this in the Manager's sublayout, so you are just moving the code that is dependent on the height, a bit later in the process. And this has the benefit that the layout is dynamic, so if the LabelField's text is changed, then layout will be invoked and your code that is dependent on the height gets re-invoked too.
It is also possible to use logic like this in sublayout():
super.sublayout(...);
if (myField.getHeight() < 100 ) {
myField.setMargin((100 - myField.getHeight())/2, 0, (100 - myField.getHeight())/2, 0);
super.sublayout(...);
}
This is not a production suitable example, hard coding a pixel height is not recommended. It is just an easy example to understand....