Layout grid with images, labels, scrollview - ios

I'm creating a layout for an iPad app that will consist of xx number of images and buttons(dynamically determined based on response from web service call) and I need to place them in a grid-like layout in a scroll view(horizontal)...
Now, I know that there are many custom UI Controls that can do something similar to this, but I haven't found one to match my 'needs'...
Basically what I want/need is that each 'entry' has an image, an overlay image, a button matching the size of the image and two labels on top of the image...
So does anybody know of a custom UI control that would match what I want?
Or do I have to write this from scratch?
I can potentially have as little as 10 entries, but also all the way up to 100+ (probably not a lot higher than this), so perhaps there is a more memory-friendly approach then what I'm considering below... - another issue is that I need to redo this every time the view appears(reason: I need to show updated data)...
I've done some initial testing of creating the grid manually, and have this so far:
int rows = 3; // fixed, will either be 2 or 3, depending on final size of images...
int columns = 8;// will be determined by response from web service
for(int i = 0; i < columns; i++)
{
for(int j = 0; j < rows; j++)
{
// Create the buttons to handle button press
UIButton *childButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
childButton.frame = CGRectMake(i * 100 + 10, j * 100 + 20, 100, 30);
[childButton setTitle:#"Test" forState:UIControlStateNormal];
[childButton addTarget:self action:#selector(presentPopoverMenu:) forControlEvents:UIControlEventTouchUpInside];
[self.scrollView addSubview:childButton];
// Create the images to display the pictures of the children
// Create the labels to display child name
// Create the labels to display pick up time
}
}

I would suggest creating custom view... Create a custom class from UIView and put all those controls on it. You should probably create initWithCustomData where custom data is what you get from web. Once you have all that you can sort them anyway you want as if they were a single simple control.
As for updating. If the whole view has fixed size just create some inner methods in custom view to change frames of subviews. If frame is dynamic you basically do the same but you have to reposition all custom views (just use UIView animations).

Related

Best way to add multiple diagonal connection lines between TableViewCells

I'm creating an app that needs to show a tableview like below image
Similar colored circles are to be matched with a line.
Which view i can add the lines?
Or need to create a new view above tableview? But still my tableview needs to be scrolled.
How can i achieve this?
Update for Bounty
I want to implement the same with incliend lines between neighbouring circles. How to achieve the same?
Demonstration below:
create design like this
Based on your requirement just hide upper line and lower line of circle
You need to create collection view in tableview cell. In collection view you create one cell. Design the same user interface like your design. Show and hide the view with matching of rule. It will not affect tableview scrolling. and with this approach you can also provide scroll in collection view cell. i can provide you coded solution if you able to provide me more information. Thanks
You can use this Third Party LIb
You need to use a combination of collection view and a table view to give support for all devices.
1.Create one collection view cell with following layout
Hide upper and lower lines as per your need
Add collection view in table view cell and managed a number of cells in collection view depending upon the current device width and item's in between spacing.
You can create a vertical label without text, set the background color with black and place it behind the circle in view hierarchy and set a width of the label as per your requirement. Then you can hide unhide the label whenever you want.
P.S.: Make sure to hide your cell separator.
I have created a demo project. You can find it here. I tried to match your requirements. You can update the collection view settings to handle the hide and show of labels.
Let me know if you have any questions.
Hope this help.
Thanks!
To connect any circle with any other circle in the cell above / below, it will be easier and cleaner to create the connection lines dynamically rather than building them into the asset as before. This part is simple. The question now is where to add them.
You could have the connection lines between every two cells be contained in the top or bottom cell of each pair, since views can show content beyond their bounds.
There's a problem with this though, regardless of which cell contains the lines. For example, if the top cell contains them, then as soon as it is scrolled up off screen, the lines will disappear when didEndDisplayingCell is called, even though the bottom cell is still completely on screen. And then scrolling slightly such that cellForRow is called, the lines will suddenly appear again.
If you want to avoid that problem, then here is one approach:
One Approach
Give your table view and cells a clear background color, and have another table view underneath to display a new cell which will contain the connection lines.
So you now have a background TVC, with a back cell, and a foreground TVC with a fore cell. You add these TVC's as children in a parent view controller (of which you can set whatever background color you like), disable user interaction on the background TVC, and peg the background TVC's content offset to the foreground TVC's content offset in an observation block, so they will stay in sync when scrolling. I've done this before; it works well. Use the same row height, and give the background TVC a top inset of half the row height.
We can make the connection lines in the back cell hug the top and bottom edges of the cell. This way circles will be connected at their centre.
Perhaps define a method in your model that calculates what connections there are, and returns them, making that a model concern.
extension Array where Element == MyModel {
/**
A connection is a (Int, Int).
(0, 0) means the 0th circle in element i is connected to the 0th circle in element j
For each pair of elements i, j, there is an array of such connections, called a mesh.
Returns n - 1 meshes.
*/
func getMeshes() -> [[(Int, Int)]] {
// Your code here
}
}
Then in your parent VC, do something like this:
class Parent_VC: UIViewController {
var observation: NSKeyValueObservation!
var b: Background_TVC!
override func viewDidLoad() {
super.viewDidLoad()
let b = Background_TVC(model.getMeshes())
let f = Foreground_TVC(model)
for each in [b, f] {
self.addChild(each)
each.view.frame = self.view.bounds
self.view.addSubview(each.view)
each.didMove(toParent: self)
}
let insets = UIEdgeInsets(top: b.tableView.rowHeight / 2, left: 0, bottom: 0, right: 0)
b.tableView.isUserInteractionEnabled = false
b.tableView.contentInset = insets
self.b = b
self.observation = f.tableView.observe(\.contentOffset, options: [.new]) { (_, change) in
let y = change.newValue!.y
self.b.tableView.contentOffset.y = y // + or - half the row height
}
}
}
Then of course there's your drawing code. You could make it a method of your back cell class (a custom cell), which will take in a mesh data structure and then draw the lines that represent it. Something like this:
class Back_Cell: UITableViewCell {
/**
Returns an image with all the connection lines drawn for the given mesh.
*/
func createMeshImage(for mesh: [(Int, Int)]) -> UIImage {
let canvasSize = self.contentView.bounds.size
// Create a new canvas
UIGraphicsBeginImageContextWithOptions(canvasSize, false, 0)
// Grab that canvas
let canvas = UIGraphicsGetCurrentContext()!
let spacing: CGFloat = 10.0 // whatever the spacing between your circles is
// Draw the lines
for each in mesh {
canvas.move(to: CGPoint(x: CGFloat(each.0) * spacing, y: 0))
canvas.addLine(to: CGPoint(x: CGFloat(each.1) * spacing, y: self.contentView.bounds.height))
}
canvas.setStrokeColor(UIColor.black.cgColor)
canvas.setLineWidth(3)
canvas.strokePath()
let image = UIGraphicsGetImageFromCurrentImageContext()!
UIGraphicsEndImageContext()
return image
}
}
You'd probably want to create a Mesh class and store the images in that model, to avoid redrawing.

How to align data points in shinobichart based on bars frame in iOS

I'm developing an iOS application and using shinobichart for iOS to display data. But I'm stuck with positioning the datapoints outside or inside the bar based on the bar frame.
I'm stuck in positioning the data point labels inside the bar or outside the bar based on bar frame. If bar is big enough to accommodate the data point I need to position the data point inside bar or else outside the bar as in the below image
In - (void)sChart:(ShinobiChart *)chart alterDataPointLabel:(SChartDataPointLabel *)label forDataPoint:(SChartDataPoint *)dataPoint inSeries:(SChartSeries *)series we need to update data points if we wish as per shinobi documentation. But what logic can help to solve such an alignment of data points.
Also I tried to with the following official shinobi example to align data point aside https://www.shinobicontrols.com/blog/customizable-datapoint-labels
But unable to modify for the requirement.
Please help to solve this riddle.
The best way for you to achieve this is to use the alterDataPointLabel method as you have mentioned. I would do something like this:
func sChart(chart: ShinobiChart!, alterDataPointLabel label: SChartDataPointLabel!, forDataPoint dataPoint: SChartDataPoint!, inSeries series: SChartSeries!) {
if Int(label.text!) > [YOUR CUT OFF VALUE]
{
label.frame.origin.y += 15
label.textColor = UIColor.whiteColor()
}
else
{
label.frame.origin.y -= 15
label.textColor = UIColor.blackColor()
}
}
This works best if you know the values your chart is going to be displayed. However as a more generic way of achieving it I would recommend comparing the y value of the data label's origin against y value of the chart canvas. Then for example you could set the it so it appears within the column if it the series was 90% of the canvas?

Update segmented control in ios without change interface

when I update segmented control text, the interface (segment's width) changed and cut some letters.
[segmentedcontoll setTitle:#"test" forSegmentAtIndex:1];
segmentedcontoll.apportionsSegmentWidthsByContent = YES;
How can I solve this ?
EDIT:
It looks like your content has outgrown the dimensions of the standard UISegmentedControl.
If you are okay with smaller font, it's possible to set the entire control to have a smaller font point size, seen here.
Another option is to configure the segments the other supported way.. With images. It's a little bit of a hack, but you can create images on the fly with the UIView Snapshotting API of views/labels configured however you want and set images for each segment instead of using text. This would allow you to create 2 line labels with fixed widths and set images for each section to be images generated from the label as the content changes. More work, but you would still be using the standard class.
The last option, which might work the best for you, is to create some other custom control that does what you would like. After all, UISegmentedControl really is just a nice button container. And it does somewhat seem like you are using the control in a non-standard way - both as a control and an input form section.
Others have gone this route before and created alternatives that you can use.
You can create a separate class as below,
class CustomSegmentedControl: UISegmentedControl {
//code for creating multi line
override func didMoveToSuperview()
{
for segment in subviews
{
for subview in segment.subviews
{
if let segmentLabel = subview as? UILabel
{
segmentLabel.numberOfLines = 0 //just change here the number of lines and check it.
}
}
}
}
}
and create an outlet in your viewcontroller as,
// Initialize
let items = ["Purple", "Green", "New Segment"]
let customSC = CustomSegmentedControl(items: items)
use customSC and do what ever you want to do, similar to segmentedControl object.

How to trace which image is currently seen in my Uiscrollview?

I am new to iOS.
I am working on UIScrollView based application. I have 3 images in UIScrollView.
I have 2 UIButtons which have selector method for Facebook and Twitter sharing.
I want to share image which is currently seen in UIScrollView to Facebook & Twitter.
I am stuck at extracting image at current scroll point.
After Googling I think something like UIPageController is the solution for me.
But I do not have any idea about how to implement it.
Please help me sort it out. Thank You!
I would say you have multiple options here, this is really a design question.
An easy (but also not very elegant) approach would be to fetch the current offset of the scroll view using its contentOffset property (depending on whether your scroll view scrolls horizontically or vertically, you have ease to use the x or y value of the contentOffset).
Next, you get the position values from your image views (again either myImageView.frame.origin.x or myImageView.frame.origin.y) and you can then calculate which of the image views is currently in the offset of the scroll view.
You can use a page controller (basically, you allow the user to end its scrolling on specific index).
Or when the user touches a button, you can retrieve the contentOffset of the scrollView and compare this value with the origin of the frame your images.
Assume, you created your images with these frames:
image1.frame = CGRectMake(0,0,320,250);
image2.frame = CGRectMake(0,250,320,250);
image3.frame = CGRectMake(0,500,320,250);
Now when you get the action:
-(IBAction)share:(id)sender {
CGPoint offset = self.scrollView.contentOffset;
if (offset.y < 250) {
//First image selected
}else if (offset.y > 500) {
//Third image selected
} else {
//Second image selected
}
}

Implement the Android Market layout in an iOS view

I'm looking for an efficient way to implement the same kind of layout that the Android market.
Right now I'm using a UITableView with custom cells. The data I'm sending from the server is something of the sort:
[
{
url: "app://url_of_content_in_the_app",
image: "http://url of the featured image",
height: 100
}
},
{
url: "app://url_of_content_in_the_app",
image: "http://url of the featured image",
height: 100
}
]
And I was thinking of updating the custom cell to support 2 or 3 buttons inside each cell, but I'm not sure this is the most efficient way to handle this. I was also thinking about a simple HTML page but I want the content to be cacheable easily.
One last point, the UITableView way only handles horizontal subdivisions such as:
_______
|__|__|
|_____|
I can't do something like:
_______
| |__|
|__|__|
You can do something like your last example (three-way cell), just have a cell two units high that you present three cells in as separate views.
Or at some point you may just decide putting views into a scroll view makes more sense, if there are not enough aspects of a UITableView you are making use of.
I would suggest putting two (or 3) custom subclasses of UIView inside the cell.
If you want them be be user interact-able - add your own UIGestureRecognizer to the view.
NSRect b = cell.contentView.bounds;
UIView *a = [[MyView alloc] initWithFrame:NSRectMake(NSRectGetMinX(b),NSRectGetMinY(b), NSRectGetWidth(b)/2., NSRectGetHeight(b))];
UIView *b; //... similarly
// set auto resize mask for a/b appropriately
[cell.contentView addSubview:a];
[cell.contentView addSubview:b];
(not checked for typos)
having a custom cell with that initialization code within it is a good idea

Resources