Implement the Android Market layout in an iOS view - ios

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

Related

How to add unique insets to specific UITableViewCells?

I have a UITableView whose insetsContentViewsToSafeArea property is set to false - this makes the tableView span the width of the screen.
The amount and different types of cells are driven by the server, so there's no way of knowing the content of the tableView.
What I'd like to to:
Assign unique insets to certain cells only.
I can't post a screenshot, so I'll try to make a quick doodle:
These three cells are all in the same UITableView:
|[This is one cell that goes edge-to-edge]|
|[Here's another one]|
|-----This cell needs its own insets-----|
Question:
What's the best way to achieve this?
What I've tried:
Overriding layoutMarginsDidChange
Trying to add layoutMargins directly in cellForRowAtIndexPath...
Create a UITableViewCell subclass for the cell with custom insets.
Then you have 2 options --
Add a subview to cell's contentView with constraints -- these will correspond to your desired insets. This view will act as your " pseudo contentView" (add cell content to it)
Play around with contentView's insets. (not sure if it'll work)
I hope this will get you started.
You can use the cell subclass for all cell cases too if you want -- with an enum style which you can set in cell for row.
enum Style {
case edgeToEdge
case withInset(inset: UIEdgeInset)
}
inside cell subclass
var insetStyle: Style = .edgeToEdge {
didSet {
//update the constraints of the pseudo content view
}
}

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.

Centering node vertically in horizontal ASStackLayout

I'm wonder what is the correct way to center textNode inside vertical ASSStackNode which is inside horizontal ASStackNode without setting any sizes?
I've tried different options with ASCenterLayout / ASRelativeLayout around vertical layout, flewGrow, flexShrink.
Only possible way that I see is static layout with minimum height around vertical layout. But wanna find if there are another way.
Images to better picture:
My layout structure:
What I get when one of text fields is empty:
What I want to see:
If your ASTextNode is empty or nil. Isn't mean node not exist. If you want hide node if it empty, you must write a simple logic for it. For exlude it Spec from calculation. What i use on ADK1.9:
- (ASLayoutSpec *)layoutSpecThatFits: (ASSizeRange)constrainedSize
{
NSMutableArray *arrayOfChildren = [NSMutableArray new];
[arrayOfChildren insertObject:self.titleNode];
if (self.textNode.text.length > 0) {
[arrayOfChildren insertObject:self.textNode];
}
ASStackLayoutSpec *verticalElementCoreStack = [ASStackLayoutSpec stackLayoutSpecWithDirection:ASStackLayoutDirectionVertical spacing:8
justifyContent:ASStackLayoutJustifyContentCenter alignItems:ASStackLayoutAlignItemsStretch
children:arrayOfChildren];
return verticalElementCoreStack;
}

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.

Layout grid with images, labels, scrollview

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).

Resources