I have the following code for a styled link label:
extension Text {
func styledLinkLabel<V: View & ShapeStyle>(with gradient: V) -> some View {
self.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0, maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius:20)
.stroke(gradient, lineWidth:15)
)
.overlay(
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
.padding(.leading)
.foregroundColor(.white)
, alignment: .leading)
.padding(5)
}
}
This is used in the code as follows:
NavigationLink(destination: RentView(viewModel: RentViewModel(Amounts(), housemates: 1)))
{
Text("1")
.styledLinkLabel(with: gradient)
}
NavigationLink(destination: RentView(viewModel: RentViewModel(Amounts(), housemates: 2)))
{
Text("2")
.styledLinkLabel(with: gradient)
}
However when I click on this in the app (screenshot below of a click in progress), the outline underneath shows. Is there any way to get rid of this?
You need to use compositingGroup:
extension Text {
func styledLinkLabel<V: View & ShapeStyle>(with gradient: V) -> some View {
self.fontWeight(.bold)
.font(.title)
.padding()
.frame(minWidth: 0, maxWidth: 250, alignment: .center)
.background(gradient)
.foregroundColor(.white)
.padding(2)
.overlay(
RoundedRectangle(cornerRadius: 20)
.stroke(gradient, lineWidth: 15)
)
.overlay(
Image(systemName: "person.crop.circle.badge.plus")
.font(.largeTitle)
.padding(.leading)
.foregroundColor(.white),
alignment: .leading
)
.compositingGroup() // <- add here
.padding(5)
}
}
Alternatively, if you don't want to modify styledLinkLabel, you can use a custom ButtonStyle:
struct CustomButtonStyle: ButtonStyle {
func makeBody(configuration: Configuration) -> some View {
configuration.label
.compositingGroup()
.opacity(configuration.isPressed ? 0.5 : 1)
}
}
NavigationLink(destination: Text("Destination")) {
Text("Text")
.styledLinkLabel(with: gradient)
}
.buttonStyle(CustomButtonStyle())
Related
I'm trying to make a converter app using SwiftUI. I added navigationlinks on the Home Screen these buttons go to the right places,no problem until here. However, I couldn't position it.
Currently, when I position them with .position, they appear in different places on different devices.
How should I do the positioning here?
I want to provide an image that will be the same on all devices as in the screenshot.
Thanks for your help.
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView{
VStack() {
// WEIGHT * MASS
NavigationLink(destination: UnitView()) {
Image(systemName: "scalemass")
.font(.system(size: 60))
.padding()
.frame(width: 150, height: 150, alignment: .center)
.background(Rectangle().fill(Color.purple.opacity(0.5))
.shadow(radius: 3)).cornerRadius(20)
.foregroundColor(.black)
.overlay(Text("Mass")
.foregroundColor(.black)
.padding()
.font(.system(size: 22)),
alignment: .bottom )}
.position(x:110, y:100)
//DISTANCE *
NavigationLink(destination: DistanceView()) {
Image(systemName: "figure.walk")
.font(.system(size: 60))
.padding()
.frame(width: 150, height: 150, alignment: .center)
.background(Rectangle().fill(Color.orange.opacity(0.5))
.shadow(radius: 3)).cornerRadius(20)
.foregroundColor(.black)
.overlay(Text("Distance")
.foregroundColor(.black)
.padding()
.font(.system(size: 22)),
alignment: .bottom )}
.position(x:110, y:100)
//TEMPERATURE *
NavigationLink(destination: TemperatureView()) {
Image(systemName: "thermometer.sun")
.font(.system(size: 56))
.padding()
.frame(width: 150, height: 150, alignment: .center)
.background(Rectangle().fill(Color.yellow.opacity(0.5))
.shadow(radius: 3)).cornerRadius(20)
.foregroundColor(.black)
.overlay(Text("Temperature")
.foregroundColor(.black)
.padding()
.font(.system(size: 21)),
alignment: .bottom )}
.position(x:280, y:-84)
// TIME *
NavigationLink(destination: TimeView()) {
Image(systemName: "clock")
.font(.system(size: 60))
.padding()
.frame(width: 150, height: 150, alignment: .center)
.background(Rectangle().fill(Color.blue.opacity(0.5))
.shadow(radius: 3)).cornerRadius(20)
.foregroundColor(.black)
.overlay(Text("Time")
.foregroundColor(.black)
.padding()
.font(.system(size: 21)),
alignment: .bottom ) }
.position(x:280, y:-444)
}
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
Sample
import SwiftUI
struct ContentView: View {
var body: some View {
NavigationView {
VStack {
Image("example-image")
.resizable()
.frame(width: 100, height: 100)
.cornerRadius(10)
NavigationLink(destination: DetailView()) {
Text("View Details")
.foregroundColor(.white)
.padding()
.background(Color.blue)
.cornerRadius(10)
}
.padding(.top, 20)
}
}
}
}
struct DetailView: View {
var body: some View {
Text("Details View")
}
}
In this example, we use a VStack to position an image and a NavigationLink. The image is resized to 100x100 and given a corner radius of 10 using the frame and cornerRadius modifiers. The NavigationLink leads to a DetailView that simply displays the text "Details View". The text inside the NavigationLink is styled to have white foreground color, padding, a blue background color, and a corner radius of 10. The .padding(.top, 20) adds some space between the image and the link.
I am new to SwiftUI and I trying to remove the blank space on my list pagination. Everytime when the list loaded the new page, a blank space is pop-up. how can I fix this?
You can see the problem by bellow attached image,
Screenshot
this is my list view
My List
List {
LazyVGrid(columns: setGridLayout(), spacing: 20) {
ForEach(viewModel.personPopularList, id: \.id) { person in
PeopleCardView(person: person)
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.id(UUID())
.frame(maxWidth: .infinity)
}
.listRowBackground(Color.white)
.listRowSeparator(.hidden)
}
.frame(maxWidth: .infinity)
.onAppear(perform: {
UITableView.appearance().contentInset.top = -20
UITableView.appearance().backgroundColor = UIColor.white
})
.listStyle(GroupedListStyle())
this is my cardview
My CardView
struct PeopleCardView: View {
#State var person: PersonPopularResult
var body: some View {
ZStack(alignment: .center) {
HStack(alignment: .center) {
WebImage(url: URL(string: Constant.POSTER_URL + (person.profilePath ?? "")))
.placeholder {
Image("placeholder")
}
.resizable()
.aspectRatio(contentMode: .fill)
.frame(width: 100, height: 100)
.clipShape(RoundedRectangle(cornerRadius: 10))
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.mPurple, lineWidth: 3))
Spacer()
VStack(alignment: .leading) {
Text("\(person.name!)")
.fontWeight(.bold)
.lineLimit(1)
.font(.system(size: 21))
.font(.headline)
Text("Popolarity Rate: \(String(format: "%.3f", person.popularity!))")
.fontWeight(.bold)
.foregroundColor(.mPurple)
.lineLimit(1)
.font(.system(size: 14))
.padding(.top, -8)
Spacer()
}
.padding([.top, .leading], 10)
Spacer()
}
.frame(width: 300, height: 100, alignment: .center)
.padding()
.background(
RoundedRectangle(cornerRadius: 15, style: .continuous)
.fill(.white)
.overlay(RoundedRectangle(cornerRadius: 10)
.stroke(Color.mPurple, lineWidth: 3))
.shadow(radius: 7)
)
}
.frame(maxWidth: .infinity, maxHeight: .infinity)
}
}
thanks for anyone can help to my problem.
As you can see from the image I have a widget with a series of elements, I have to put at the end of the series of elements then the word Next update which must find some at the end of the widget.
The problem is:
if there are few elements, Next update is too high.
if there are many elements the Next update message is not shown.
Can you give me a hand?
P.s.
If you think it should be written differently let me know, thank you in advance.
struct GitCommitWidgetEntryView : View {
var entry: ProviderCommit.Entry
#Environment(\.colorScheme) var colorScheme
let firstColor: UInt = getDate() ? 0x4688B4 : 0x030721
var body: some View {
GeometryReader { geometry in
if(entry.loading){
if(!entry.error){
VStack() {
if(entry.user != ""){
HStack {
Spacer()
Text("\(entry.user) (\(entry.commits.count))")
.font(.caption)
.foregroundColor(Color.black)
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(1),
y: CGFloat(1)
)
Spacer()
}
.background(Color(hex: 0xff9800))
}
if(entry.commits.count > 0){
ForEach(entry.commits, id:\.id){
item in
Text(item.commit.message)
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(1),
y: CGFloat(1)
)
Text("\(item.author.login) \(convertDate(date: item.commit.author.date))")
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(1),
y: CGFloat(1)
)
Divider()
}
.frame(alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
}else{
Text("There are no repositories.")
.font(.caption)
.foregroundColor(Color.black)
.padding(2)
.background(Color.white.opacity(0.4))
.cornerRadius(5)
.padding(.bottom, 3)
.padding(.horizontal, /*#START_MENU_TOKEN#*/10/*#END_MENU_TOKEN#*/)
.multilineTextAlignment(.center)
.frame(maxWidth: .infinity, maxHeight: /*#START_MENU_TOKEN#*/.infinity/*#END_MENU_TOKEN#*/, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
}
HStack {
Spacer()
Text("Next update")
.font(.caption)
.foregroundColor(Color.black)
.multilineTextAlignment(.center)
.shadow(
color: Color.black,
radius: 1.0,
x: CGFloat(1),
y: CGFloat(1)
)
Spacer()
}
.background(Color(hex: 0xff9800))
}
.background(LinearGradient(
gradient: Gradient(colors: [
Color(hex: firstColor),
Color(hex: 0xffffff)
]),
startPoint: .top,
endPoint: .bottom)
)
}else{
VStack() {
Text("No user exist.")
.font(.caption)
.foregroundColor(Color.black)
.padding(2)
.background(Color.white.opacity(0.4))
.cornerRadius(5)
.padding(.bottom, 3)
.padding(.horizontal, /*#START_MENU_TOKEN#*/10/*#END_MENU_TOKEN#*/)
.multilineTextAlignment(.center)
}
.frame(maxWidth: .infinity, maxHeight: /*#START_MENU_TOKEN#*/.infinity/*#END_MENU_TOKEN#*/, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.background(Color.red)
}
}else{
VStack() {
Text("No user selected.")
.font(.caption)
.foregroundColor(Color.black)
.padding(2)
.background(Color.white.opacity(0.4))
.cornerRadius(5)
.padding(.bottom, 3)
.padding(.horizontal, /*#START_MENU_TOKEN#*/10/*#END_MENU_TOKEN#*/)
.multilineTextAlignment(.center)
}
.frame(maxWidth: .infinity, maxHeight: /*#START_MENU_TOKEN#*/.infinity/*#END_MENU_TOKEN#*/, alignment: /*#START_MENU_TOKEN#*/.center/*#END_MENU_TOKEN#*/)
.background(Color.green)
}
}
}
}
The approach you need is to separate "labels to be always on screen" and "growing list", schematically it should be like
VStack {
Text("Header label")
Spacer()
Text("Footer label")
}
.background(
VStack {
Text("Header label").opacity(0) // for content offset
// or constant height spacer
ForEach ... // list here
}
}
I have a button which I am unable to align to the top left with topLeading.
What I hope to accomplish:
my code:
var body: some View {
ZStack {
ZStack(alignment: .topLeading) {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(.black)
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color("buttonShadow"), radius: 10, x: 0, y: 10)
}
Spacer()
}
}
}
But I get this:
The issue is that your wrapping views (two ZStacks) by default will take up only the space of their content, which is only the button. If you add a frame to allow the wrapper to expand you'll see the alignment working as you expect.
var body: some View {
ZStack {
ZStack {
Button(action: { self.show.toggle() }) {
HStack {
Spacer()
Image(systemName: "list.dash")
.foregroundColor(.black)
}
.padding(.trailing, 20)
.frame(width: 90, height: 60)
.background(Color.white)
.cornerRadius(30)
.shadow(color: Color.gray, radius: 10, x: 0, y: 10)
}
Spacer()
}
.frame(
maxWidth: .infinity,
maxHeight: .infinity,
alignment: Alignment.topLeading
)
}
}
Add background space consumer, like below (tested with Xcode 11.4)
ZStack(alignment: .topLeading) {
Color.clear // << here !!
Button(action: { self.show.toggle() }) {
I have some SwiftUI function. I want to show my button in bottom left, but it shows top left.
struct NewRecordButton: View {
var body: some View {
ZStack (alignment: .bottomTrailing) {
HStack (alignment: .bottom) {
Spacer()
Button(action: { },
label: {
Text("⌂")
.font(.system(.largeTitle))
.frame(width: 35, height: 30)
.foregroundColor(Color.white)
.padding(.bottom,4)
}) .background(Color.black)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
}
}
}
}
Any ideas?
Here is possible variant
ZStack (alignment: .bottomTrailing) {
Rectangle().fill(Color.clear)
HStack (alignment: .bottom){
Button(action: {
}, label: {
Text("⌂")
.font(.system(.largeTitle))
.frame(width: 35, height: 30)
.foregroundColor(Color.white)
.padding(.bottom,4)
})
.background(Color.black)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.3),
radius: 3,
x: 3,
y: 3)
Spacer()
}
}
Although it's possible, but you should try NOT to use dummy views to arrange other views!
For pushing a view down, you should use a VStack and a Spacer together
VStack {
Spacer()
// bottomView
}
So it should be like:
ZStack {
VStack {
Spacer() // This will push it down, since it is in a `VStack`
HStack {
Button("⌂") {}
.font(.largeTitle)
.frame(width: 35, height: 30)
.foregroundColor(.white)
.padding(.bottom, 4)
.background(Color.black)
.cornerRadius(10)
.shadow(color: Color.black.opacity(0.3), radius: 3, x: 3, y: 3)
Spacer() // This will push it left, since it is in a `HStack`
}
}
}