Programmatic Paginated Navigation in Swift / UI Builder - iphone

I'm a senior Ruby developer, and just getting into Swift and iPhone development, but can't seem to make heads or tails of where to begin with answering my own question. My apologies ahead of time if I sound extremely newb!
My goal is to take a set of data ( in Ruby, it would be a hash or JSON ), and form x views from it. For example, the data might be :
my_page_info = {
{
title: "Page 1",
content: "Blah blah blah",
additional_info: "Some more blah"
},
{
title: "Page 2",
content: "Blah blah blah",
additional_info: "Some more blah"
},
{
title: "Page 3",
content: "Blah blah blah",
additional_info: "Some more blah"
}
}
Side Question.. What would be the best way to write that kind of information in Swift? Assuming it wouldn't be in JSON..
Then I'd assume, it would be proper architecture to use just one view in the UI Builder that would represent all available data in this array. Where my_page_info would populate 3 different labels defined as #IBOutlet's arranged in my UI View Controller, and then interpolate the values.
Lastly, I wanted to have a back and forward button that would allow me to navigate these items. I looked everywhere for such a system icon, but it seems like it doesn't exist. At least not within the UI Builder. I imagine it can only be done programmatically, and then I'd have to import my own images to represent those buttons.
Would anyone know any part of my question, or direct me in the right direction?
Thanks!

From Airspeed Velocity's answer to my question, you see that a struct would be the way to go for your data:
struct Page {
let title: String
let content: String
let additionalInfo: String
}
var myPageInfo = [
Page(title: "Page 1", content: "Blah blah blah", additionalInfo: "some more blah"),
Page(title: "Page 2", content: "Blah blah blah", additionalInfo: "some more blah"),
Page(title: "Page 3", content: "Blah blah blah", additionalInfo: "some more blah"),
]
Note the removal of the underscores from variable names.
Then, I think you would want a tableview, where you set up a single prototype cell in Interface Builder with fields for each corresponding field in your data.
Edit: you probably just want the title in the cell and you would pass the other info through a segue (see below) to the page where everything is laid out all nice.
Then your cellForRowAtIndexPath method would look like:
override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("pageCell", forIndexPath: indexPath) as! PageCell
cell.titleLabel.text = "myPageInfo[indexPath.row].title"
cell.contentLabel.text = "myPageInfo[indexPath.row].content"
cell.additionalInfoLabel.text = "myPageInfo[indexPath.row].additionalInfo"
return cell
}
Your prepareForSegue method in the tableViewController would pass the values for the data selected to the ViewController that you set up to display the info.
I'm not sure what you're looking for in the last part, but if you use a navigationController, you automatically get a Back button (which in your case would go back to the tableViewController)

Related

How to control accessibility voiceover text for the SwiftUI Image

For the SwiftUI Image element, the voiceover template is seems "accessibility label - image - image name", e.g. for
var body: some View {
Image(systemName: "equal")
.accessibilityLabel("my label")
}
I am getting voiceover response "my label image equal".
Is it possible for voiceover to only say "my label", and not pronounce the "image equal" part?
Once the element gets the focus, the default trait(link, button, label, etc) will be played after accessibilityLabel text. That's the reason it reads out as "my label -> image"
To add or remove the default trait following methods can be used :
.accessibilityAddTraits
.accessibilityRemoveTraits
Example
To recognize an image as a button:
Add .isButton trait and remove the .isImage trait, now VoiceOver can read the description of Image as "my label -> button"
struct ContentView: View {
var body: some View {
Image(systemName: "equal")
.accessibilityLabel("my label")
.accessibilityAddTraits(.isButton)
.accessibilityRemoveTraits(.isImage)
}
}
As an element can have multiple traits, remove the ones you don't want the voiceover to read.

SwiftUI Table reorder columns - macOS

Is it possible to reorder columns in SwiftUI Tables using Drag and Drop?
Apple has introduced "Table" in SwiftUI 3.0 in summer 2021. It's the SwiftUI equivalent of NSTableView.
I was not able to find any hints in apples documentation regarding column reordering.
I'm speaking of reordering as we all know from NSTableViews like the one in Finder.
I used the sample code provided by Apple.
struct Person: Identifiable {
let givenName: String
let familyName: String
let id = UUID()
}
#State private var people = [
Person(givenName: "Juan", familyName: "Chavez"),
Person(givenName: "Mei", familyName: "Chen"),
Person(givenName: "Tom", familyName: "Clark"),
Person(givenName: "Gita", familyName: "Kumar"),
]
var body: some View {
Table(people, selection: $selectedPeople, sortOrder: $sortOrder) {
TableColumn("Given Name", value: \.givenName)
TableColumn("Family Name", value: \.familyName)
}
}
I also tried to build the table columns dynamically with for each. but that throws a bunch of debug errors.
#State private var columns = [
TableColumn("Given Name", value: \Person.givenName),
TableColumn("Family Name", value: \Person.familyName)
]
var body: some View {
Table(people, selection: $selectedPeople, sortOrder: $sortOrder) {
ForEach (columns, id: \.self) { column in
column
}
}
}
Seems like ForEach is not compatible with TableColumns:
Generic struct 'Table' requires that 'ForEach<[TableColumn<Person, Never, Text, Text>], TableColumn<Person, Never, Text, Text>, some AccessibilityRotorContent>' conform to 'TableColumnContent'
Static method 'buildBlock' requires that 'ForEach<[TableColumn<Person, Never, Text, Text>], TableColumn<Person, Never, Text, Text>, some AccessibilityRotorContent>' conform to 'TableColumnContent'
First of all, you should know that UITableView has only one column.
So to help you with your problem, I can suggest you do these steps.
To have a tableView with multiple columns, create multiple UITableView, and put them together on the UI. (in a way that each tableView will play as one column!)
Now you have some tables that sit next to each other, and each table will be playing as one column.
Now problem is that each table has its own scroll.
As UITableview is derived from UIScrollview you can get the scroll amounts in the 'scrollViewDidScroll' delegate method.
On this delegate method, get the offset of the scrollView which is being scrolled, and assign that value to the other tableViews.
firstTableview.contentOffset = scrollview.contentOffset
Now all tableViews will be scrolling simultaneously with the same px height and feels that they play as a single TableView with multiple columns.
In the end, you want to make the user be able to reorder the table columns (actually you have to make tableViews to be able to change their position)
To achieve this, you have to create a UICollectionView that every cell of a collectionView will be one of your tableView. and then use some packages like 'Reorder' to make cells to be reordered.
(Reorder GitHub address: https://github.com/pikachu987/Reorder)
summary:
Create a UICollectionView with 3 cells. (cell.hight = yourPageHeigh, cell.width = yourPageWidth/3)
Use 'Reorder' package to make cells reorderable.
Each cell of the collectionView will contain one of your UITableView.
By using 'scrollViewDidScroll' method, make all tables scroll simultaneously.
Now you have a table that has some columns and columns can be reordered.

Swift: How does this create a binary tree?

So I am following an online tutorial and I understand everything except this part. The person explains to me this creates a binary tree so to speak where one item is linked to two items. In this case a page is linked to two pages. I don't understand how this works in this example where struct Adventure creates the binary tree. Any help will be appreciated. Currently, I feel really bad for not understanding this at all.
import Foundation
class Page {
let story: Story
typealias Choice = (title: String, page:Page)
var firstChoice: Choice?
var secondChoice: Choice?
init(story: Story) {
self.story = story
}
}
extension Page {
// adds the page
func addChoiceWith(title: String, story:Story) -> Page {
let page = Page(story:story)
return addChoiceWith(title: title, page: page)
}
// creates branches
func addChoiceWith(title: String, page: Page) -> Page {
switch (firstChoice, secondChoice) {
case (.some, .some) : return self
case (.none, .none), (.none, .some): firstChoice = (title, page)
case (.some, .none): secondChoice = (title,page)
}
return page
}
}
struct Adventure {
static var story: Page {
let returnTrip = Page(story: .returnTrip)
let touchdown = returnTrip.addChoiceWith(title: "Stop and Investigate", story: .touchDown)
let homeward = returnTrip.addChoiceWith(title: "Continue home to Earth", story: .homeward)
let rover = touchdown.addChoiceWith(title: "Explore the Rover", story: .rover)
let crate = touchdown.addChoiceWith(title: "Open the Crate", story: .crate)
homeward.addChoiceWith(title: "Head back to Mars", page: touchdown)
let home = homeward.addChoiceWith(title: "Continue Home to Earth", story: .home)
let cave = rover.addChoiceWith(title: "Explore the Coordinates", story: .cave)
rover.addChoiceWith(title: "Return to Earth", page: home)
cave.addChoiceWith(title: "Continue towards faint light", story: .droid)
cave.addChoiceWith(title: "Refill the ship and explore the rover", page: rover)
crate.addChoiceWith(title: "Explore the Rover", page: rover)
crate.addChoiceWith(title: "Use the key", story: .monster)
return returnTrip
}
}
Each Page represents a node in the tree and each Choice represents branch. A Story is like the content of the node. firstChoice.page and secondChoice.page represents the two children of a node.
The Adventure.story property creates a tree and returns the root node. You can access all other nodes using the root:
Adventure.story.firstChoice.page.secondChoice.page
Now, let's look at how the tree is constructed. Note that this isn't a standard binary tree that you see all the time. Some of the nodes have their parents as children. But each node does have two children.
I will turn the code into pseudocode. You can follow this code, and on a piece of paper, draw the tree yourself.
Create a node called "returnTrip"
Add a child to returnTrip called "touchDown"
Add a child to returnTrip called "homeward"
Add a child to touchDown called "rover"
Add a child to touchDown called "crate"
Connect homeward back to touchDown
Add a child to homeward called "home"
Add a child to rover called "cave"
Connect rover to home
Add a child to cave called "droid"
Connect cave to rover
Connect crate to rover
Add a child to crate called "monster"

YouTube in UITableView

Ok so I'm finding this insanely difficult to find for something that is done a lot. I'm struggling to find a way of putting the newest YouTube videos from a user into a UITableView.
I've tried this but it's out of date and I gets heaps of errors: http://code.google.com/p/gdata-objectivec-client/downloads/detail?name=gdata-objectivec-client-1.11.0.zip
Aside from using a UIWebView, are there any good tutorials, that work, on putting YouTube videos in a UITableView?
Let's take an example.. for Nethfel user; click on his playlist; in the link bar you will see "http://www.youtube.com/watch?v=4nx7g60Ldig&list=UUANsW00CkQnNnnUyuC1cygw"
now .. we take the playlist "number" UUANsW00CkQnNnnUyuC1cygw
and.. we will make an JSON request..max 50 results
http://gdata.youtube.com/feeds/api/playlists/UUANsW00CkQnNnnUyuC1cygw?v=2&alt=jsonc&max-results=50
You can replace JSON with JSONC - you will se minor changes in your results;
This will be your request at the beginning of your app
Now we must "interpret/translate" the next result:
{
apiVersion: "2.1",
data: {
id: "UUANsW00CkQnNnnUyuC1cygw",
author: "Nethfel",
title: "Uploaded videos",
description: "",
thumbnail: {
sqDefault: "http://i.ytimg.com/vi/4nx7g60Ldig/default.jpg",
hqDefault: "http://i.ytimg.com/vi/4nx7g60Ldig/hqdefault.jpg"
},
content: {
5: "http://www.youtube.com/p/UUANsW00CkQnNnnUyuC1cygw"
},
totalItems: 17,
startIndex: 1,
itemsPerPage: 50,
items: [
{
id: "UUGCa8nZNU7uOfDF3zV9AxkJtJSuX5gHGI",
position: 1,
author: "Nethfel",
video: {
id: "4nx7g60Ldig",
uploaded: "2011-11-02T12:32:03.000Z",
updated: "2013-01-07T18:26:41.000Z",
uploader: "nethfel",
category: "Howto",
title: "iOS Passing Data Between View Controllers Technique 1",
description: "This video discusses one of the most basic techniques for passing data between view controllers in an iOS application. This technique uses storing a local iVar in one class and passing it to the second class about to be displayed on the screen. Although this is a very simple example using an NSString, it can be applied using any other type of data as well - whether it be a collection or a custom data model object.",
thumbnail: {
sqDefault: "http://i.ytimg.com/vi/4nx7g60Ldig/default.jpg",
......
You have all the elements: title, thumbnail, link to page, etc...
you need to PARSE (extract) this JSON response.. put it in an TableView..
at click on cell, open a new "Detail" page.. were you can have LBYouTubeView for iOS
If you can get a YouTube video to play in a UIView, you can embed that in a UITableView controller cell.

How to display contents of a JSON file on separate UITableviews?

I have this JSON file (the parsing OK, the problem is displaying the contents as I'll describe here) that I need to display in separate UITableViews:
{
"Programs": [
{"link1": "http://www.myWebSite1.aspx",
"program name": "Live Show at 9",
"speaker": "Dr. Speaker 1"
"day1": "Sunday"
"day2": "Monday"
"day3": "Tuesday"},
{"link2": "http://www.myWebSite2.aspx",
"name": "Dr. Speaker 2",
"speaker": "Live Show at 10"
"day1": "Sunday"
"day2": "Monday"
"day3": "Tuesday"
"day4": "Wednesday"}
]
}
The user will make his first choice based on the program/speaker, then a second UITableView should pop-up presenting the days of the week for him to choose from. So, this second UITableView will display the contents of day1, day2, day3, etc...
How can I make such a subdivision, with the contents of this JSON file? Thank you!
You need to declare jsonArray of NSDictionary in new UITableView Controller class and then synthesize it. Fill up that array and new UITableView pass this array in cellForRowAtIndexPath. For more details go through the link (for just idea)
http://gauravstomar.blogspot.com/2010/06/uitableviewcell-tableviewuitableview.html