Swift ui widget list of items that take up too much space - swift

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
}
}

Related

How to remove big blank space on my list pagination [SwiftUI]

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.

Autolayout in SwiftUI

Good afternoon community,
Any way to autolayout in swiftui so that my view looks good both in portrait and landscape?
I've already tried everything with geometry render and frame (.infinity) but I can't get it.
someone who has managed to be able to have his ap in both modes with swuftui?
I attach my code and a couple of images.
import SwiftUI
struct OnBoardingView: View {
var ImageOnTop:some View{
Image("headerPicture")
.resizable()
}
var Title:some View {
Text("Hey You")
.font(.custom("Montserrat-Medium", size: 48))
.foregroundColor(.white)
}
var subTitle:some View{
Text("Out With A Porpuse ")
.font(.custom("Montserrat-SemiBold", size: 16))
.foregroundColor(.white)
}
var secondSubtitle:some View{
Text("Find and build communities with people in your area. \n #GoodbyeCatfish \n #HellowConnections")
.font(.custom("Montserrat-Regular", size: 16))
.foregroundColor(.white)
.multilineTextAlignment(.center)
}
var navigatinButton:some View{
VStack(alignment:.center){
NavigationLink(
destination: CreateAccountView(),
label: {
Text("Create Account")
})
.font(.custom("Montserrat-Medium", size: 18))
.foregroundColor(.white)
.frame(width: 230, height: 42, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.yellow, lineWidth: 1.8))
HStack{
Text("Already have an account?")
.font(.custom("Montserrat-Regular", size: 12))
.foregroundColor(.white)
.multilineTextAlignment(.leading)
NavigationLink(
destination: LoginView(LoginViewM: LoginViewModel()),
label: {
Text("Log In")
})
.font(.custom("Montserrat-Regular", size: 12))
.foregroundColor(.yellow)
}
}
}
var lastString: some View{
HStack{
Text("By using this app you agree with the")
.foregroundColor(.white)
.font(.custom("Montserrat-Medium", size: 11))
Text("terms of services")
.underline(true, color: .yellow)
.foregroundColor(.yellow)
.font(.custom("Montserrat-Medium", size: 11))
}
.padding(30)
}
var body: some View {
GeometryReader{ geometry in
NavigationView{
VStack(spacing:40){
VStack(alignment: .center,spacing:15){
ImageOnTop
.frame(width: geometry.size.width, height: 270)
Title
subTitle
}
.frame(width: geometry.size.width, height: 270)
secondSubtitle
.frame(width: geometry.size.width, height: 75, alignment: .center)
.padding(30)
navigatinButton
Spacer(minLength: 14)
lastString
Spacer().frame(height:20)
}
.edgesIgnoringSafeArea(.all)
.background(Color.black)
}
.frame(width: geometry.size.width, height: geometry.size.height)
.navigationBarBackButtonHidden(true)
}
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
OnBoardingView()
.previewDevice(PreviewDevice(rawValue: "iPhone 12"))
.previewDisplayName("iPhone 12")
}
}
Here is a version of your code that works for all screen sizes and positions. Less is more in SwiftUI. The more the hardcoded values the harder it is for SwiftUI to do the adjusting.
struct OnBoardingView: View {
var ImageOnTop:some View{
//Just to simulate,I switched to a system image you will have to adjust for your own
Image(systemName: "square")
.resizable()
.foregroundColor(.blue)
}
var Title:some View {
Text("Hey You")
.font(.custom("Montserrat-Medium", size: 48))
.foregroundColor(.white)
}
var subTitle:some View{
Text("Out With A Porpuse ")
.font(.custom("Montserrat-SemiBold", size: 16))
.foregroundColor(.white)
}
var secondSubtitle:some View{
VStack{
Text("Find and build communities with people in your area.")
.lineLimit(1)
Text("#GoodbyeCatfish \n #HellowConnections")
}
.font(.custom("Montserrat-Regular", size: 16))
.foregroundColor(.white)
.multilineTextAlignment(.center)
.minimumScaleFactor(0.5)
}
var navigatinButton:some View{
VStack(alignment:.center){
NavigationLink(
destination: Text("CreateAccountView()"),
label: {
Text("Create Account")
})
.font(.custom("Montserrat-Medium", size: 18))
.foregroundColor(.white)
//Don't fix the size or thre won't be any differences between devices
.frame(minWidth: 0, idealWidth: 230, maxWidth: 230, minHeight: 0, idealHeight: 42, maxHeight: 42, alignment: .center)
.overlay(RoundedRectangle(cornerRadius: 18)
.stroke(Color.yellow, lineWidth: 1.8))
HStack{
Text("Already have an account?")
.font(.custom("Montserrat-Regular", size: 12))
.foregroundColor(.white)
.multilineTextAlignment(.leading)
NavigationLink(
destination: Text("LoginView(LoginViewM: LoginViewModel()"),
label: {
Text("Log In")
})
.font(.custom("Montserrat-Regular", size: 12))
.foregroundColor(.yellow)
}
}
}
var lastString: some View{
HStack{
Text("By using this app you agree with the")
.foregroundColor(.white)
.font(.custom("Montserrat-Medium", size: 11))
Text("terms of services")
.underline(true, color: .yellow)
.foregroundColor(.yellow)
.font(.custom("Montserrat-Medium", size: 11))
}
.padding(30)
}
var body: some View {
GeometryReader{ geometry in
NavigationView{
VStack{
ImageOnTop
.frame(height: geometry.size.height * 0.2)
VStack{
Title
subTitle
}.frame(height: geometry.size.height * 0.25)
Spacer()
secondSubtitle
//You can give spaces more weight by addign spacers
//This makes the space above the button twice as wide as the bottom
Spacer()
Spacer()
navigatinButton
Spacer()
lastString
}
.background(Color.black)
.edgesIgnoringSafeArea(.all)
.navigationBarHidden(true)
}
.navigationBarBackButtonHidden(true)
}
}
}

How to remove border outline when clicking on styled link label?

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

SwiftUI unable to align button with topLeading

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() }) {

SwiftUi bottom left button dont show

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`
}
}
}