How to add a Button to the end of Text in SwiftUI? - swiftui

I'd like to create a UI similar to Apple's in Game Center Settings, where there is a tappable link at the end of text:
I'm using SwiftUI. I tried to combine Text and Button in several ways:
Form {
Text("A social gaming service that lets you interact with friends, track and compare scores and achievements, challenge other players, and compete in mulitplayer games.")
Button("See how your data is managed...", action: {})
Button(action: {}, label: {
Text("A social gaming service that lets you interact with friends, track and compare scores and achievements, challenge other players, and compete in mulitplayer games.").foregroundColor(.black)
Text("See how your data is managed...")
})
Group {
Text("A social gaming service that lets you interact with friends, track and compare scores and achievements, challenge other players, and compete in mulitplayer games.")
Button("See how your data is managed...", action: {})
}
HStack {
Text("A social gaming service that lets you interact with friends, track and compare scores and achievements, challenge other players, and compete in mulitplayer games.")
Button("See how your data is managed...", action: {})
}
}
But none of these combinations worked:
I would ideally like to avoid using an NSAttributedString, as I want to use SwiftUI components, and only want the blue portion to be tappable.
How do I append a Button to Text so that it's text is aligned to the baseline of the text?

It's unlikely that this type of layout will be available in SwiftUI anytime soon. The major complexity comes from the fact that the Button text must have some knowledge about (A) the frame of the Text block (e.g. to know where to place overflowing content like the word "data" in the original example), (B) to align the Button's first baseline to the Text's last baseline, and (C) to align the Button's leading edge to the exact end of Text on the last line (e.g. it can't just to the right of the frame, otherwise you'll get HStack behavior).
One workaround is to follow a different pattern (i.e. the one in the Safari Settings) where the components are vertically placed:
This is a far easier layout to achieve in SwiftUI:
Section(footer:
VStack(alignment: .leading) {
Text("Allow websites to check if Apple Pay is enabled and if you have an Apple Card account.")
Button("About Safari & Privacy...", action: {})
}) {
EmptyView()
}

Related

WinUI3 : Incrementally add contents to ListView On scroll

I am working on WinUI 3 desktop application in C++. I was trying to achieve an experience where when we scroll ListView, we will incrementally add rows to the end of the listviews dropdown during runtime.
For example, I might have 100,000 results to fit in a list view, I only want to show a limited number of contents in the list view, then as the user scrolls I'll add more contents to the list view.
I was not able to get any scroll-based events in ListView directly, so I extracted the ScrollViewer from the list view and handled the ViewChanged event. This event was fired when the scroll happened. But I was not able to get how many rows were scrolled or currently which row is been scrolled.
I want to get how many rows are scrolled so that I can insert enough rows to the end of the ListViews Item Source. It would be of great help if you could help me with this.
Thank You

How to scroll two lists synchronously in swiftui

I have two related lists side-by-side. I want to scroll any one of the lists, and the other one can scroll synchronously. Is there any way to achieve the effect? Any help will be appreciated.
struct ScrollTwoListsSynchronously: View {
let dataSet = [1,2,3,4,5]
var body: some View {
HStack{
List{
ForEach(dataSet,id:\.self){data in
Text(String(data))
}
}
.listStyle(PlainListStyle())
List{
ForEach(dataSet,id:\.self){data in
Text(String(data))
}
}
.listStyle(PlainListStyle())
}
}
}
Supplementary information:
Seeing the comments and answers below, I realize that my problem description is not comprehensive enough. Sorry!
I want to show some data in two columns according the layout need. The left one shows the odd numbered data(NO1\NO3...), and the right one shows the even numbered data(NO2\NO4...). The 2 columns may have the same number of lines, if not, the left column has 1 more line than right.
Putting all of the data into a single list or a two-column grid seems a good choice. But I also want to use the multiple selection function that comes with the list, in order to select some data items. If two data items are in the same row of the list. I'm afraid I cannot choose only one of them. Based on this consideration, I wonder if I could use two lists to show the two column data synchronously to keep NO1 & NO2(NO3 & NO4, NO5 & NO6,...) always in the same line. If feasible, I can directly use the multi-select function of list to select any items, without creating a custom function.

Picker View data disappears too quickly

Scenario:
Application is tab-based; one tab is a container view having a 'Picker (Data) View'.
Picker View: the Picker is initially loaded with data via #State -> #Binder.
A 'Front Page' (Greetings) View is initially displayed over the Picker View within a ZStack{}.
User Acknowledges the front page which disappears to reveal the Picker View (#2).
Note: Data is received by the Picker per debug check.
The hidden Picker View shows the initial data.
Problem:
The revealed Picker View becomes empty; after dismissing the Front Page/View.
The following is a debug listing via BreakPoint of data:
Observation:
I want to access the data source ASAP to populate the Picker View to avoid having the user wait for the data. Hence the data is initially access prior to revealing the Picker View.
However,
the Picker View apparently gets re-rendered just prior to being displayed.
Note: I see the populated picker page if I comment-out the front-page code.
👉 I've added a boolean filter to avoid calling the Picker with an empty data payload.
Question:
How do I make the data more permanent; that is, stay until it is dismissed?
Do I have to make a concrete copy of a #Binding variable?
Non-SwiftUI fix:
Use a Singleton for the persistent data vector; and hence not influenced by the life of the controlling View:
final class DataSource {
static let shared = DataSource()
var myVar:String = "Hello World"
var countryNames: [String]?
}
This is so simple that it's elegant.
Still, I would like to use combine here, but the data life is too volatile.
I plan to review this paradigm further into my project as I become more proficient in Combine.
If anyone has a SwiftUI/Combine method of accessing, holding/sharing data that doesn't require a Singleton object, please post.

How to hide the Horizontal Scroll bar

I have 2 APEX interactive grids as a master detail on the same page. The top grid (master) has a vertical scroll bar which I want but there are only a few columns in each row and it does not need a horizontal bar.
I had to change the Pagination to scroll from Page and set the heading to region and the height to 400 px so both reports are displayed on one page.
I tried setting body overflow to hide in template options but I still have a big horizontal scroll bar in the middle of my page.
In addition to this, it seems the columns keep resizing themselves to take up all the space even though I made them very small and saved the report. The scroll bar does not really scroll since it has no place to go.
Any help on how to get rid of the scroll bar would be greatly appreciated.
The only way to hide it is for the columns to be smaller so that there is no reason for it to exist(afaik). You say you already resized them and saved the report and it didn't work. I am not sure if it will work but we have this code in the attributes-advanced-javascript initialisation code in one of out environments that seems to do what you want:
function(config) {
// Logically we want to do this: config.views.grid.features.stretchColumns = false;
// but the server may not generate the views, grid, or features objects
// so we must check for and add if needed each one using this code
var o = config;
"views.grid.features".split(".").forEach(function(p) {
if ( !o[p] ) {
o[p] = {};
}
o = o[p];
});
o.stretchColumns = false;
return config;
}
Try it and maybe it will work for you, not a guaranteed answer, but just something to try.

Tab Bar Controller / Segue Issue

I am working with 4 views using a Tab Bar. The first view has a tableview of rounds of golf. The second view allows the user to enter data for a new round. I have a button on the "Add Round" view that saves the inputted data to Core Data. When the user saves the round I want the view to segue back to the "home screen" where the rounds are displayed. I created a segue called "SavetoHomeSegue" in storyboard.
This is the code I use to switch between the views
[self performSegueWithIdentifier:#"SavetoHomeSegue" sender:self];
[self.tabBarController setSelectedIndex:0];
Here is my issue: When I switch back to the "Home Screen" the tableview now appears for the first tab AND the second tab. Also, it doesn't seem like the "Add Round" view was properly unloaded as I was previously having to manually clear the data inputs in the textfields. How do I transition from one tab to another and properly unload the views? I have posted my views below:
Home Screen View -
Add Round View -
You definitely shouldn't be segueing between tab bar vc's. Just save the data and refresh the other view on viewWillAppear. Call setSelectedViewController when necessary, but never segue between tab bar vc's.