In this chart I'd like to have control over the number of xAxis labels as well as the placement, however I want the framework to control what is actually in the label, i.e. I don't want custom xAxis labels.
See my code below and the resulting chart.
I would instead like (1) the first date to be on the far left and (2) the last date to not be cut off?
Chart {
ForEach(unwrappedVo2Max) { vo2MaxSample in
AreaMark(
x: .value("Date", vo2MaxSample.startDate),
y: .value("Cardio Fitness", vo2MaxSample.quantity.doubleValue(for: HKUnit(from: "ml/kg*min")))
)
//.interpolationMethod(.cardinal)
.opacity(0.6)
.alignsMarkStylesWithPlotArea()
.foregroundStyle( .linearGradient(
colors: \[Color.clear, TrackerConstants.AppleFitnessPurple\],
startPoint: .bottom, endPoint: .top
))
LineMark(
x: .value("Date", vo2MaxSample.startDate),
y: .value("Cardio Fitness", vo2MaxSample.quantity.doubleValue(for: HKUnit(from: "ml/kg*min")))
)
.lineStyle(StrokeStyle(lineWidth: 2))
.foregroundStyle(TrackerConstants.AppleFitnessPurple)
}
}
.frame(height: TrackerConstants.chartHeight)
.padding(.horizontal)
.chartYScale(domain: SwiftChartHelpers.getYScaleMin(values: unwrappedVo2Max.map { $0.quantity.doubleValue(for: HKUnit(from: "ml/kg*min")) }, padding: 10)...SwiftChartHelpers.getYScaleMax(values: unwrappedVo2Max.map { $0.quantity.doubleValue(for: HKUnit(from: "ml/kg*min")) }, padding: 10.0))
.chartYAxis {
AxisMarks(position: .leading)
}
Related
I cannot change the location of the Mark within the day.
I have tried changing the Marks and the x axis values (which are Date objects) to the start of the day, but it doesn't change the plot point. I assume it is rounding my Dates to the middle of the day (noon). How do I make my marks appear at the beginning of the day?
Notice the marks in my line chart do not start at the bottom left, and each mark never appears on a vertical line.
struct PackagesReceivedChart: View {
var plottablePackageData: [PlottablePackageData]
var calendarComponent: Calendar.Component
var xAxisDates : [Date]
let underGradient = LinearGradient(
gradient: Gradient (
colors: [
.red.opacity(0.7),
.red.opacity(0.5),
.red.opacity(0.3),
]
),
startPoint: .top,
endPoint: .bottom
)
var body: some View {
Chart{
ForEach(plottablePackageData){
LineMark(
x: .value("time", $0.timeframe, unit: calendarComponent),
y: .value("packagesReceived", $0.count)
)
.foregroundStyle(.red)
.lineStyle(StrokeStyle(lineWidth: 3))
.symbol(){
Circle()
.fill(.red)
.frame(width: 10)
}
AreaMark(x: .value("time", $0.timeframe, unit: calendarComponent),
y: .value("packagesReceived", $0.count))
.interpolationMethod(.linear)
.foregroundStyle(underGradient)
}
}
.chartXAxis{
AxisMarks(values: xAxisDates)
}
.chartYAxis{
AxisMarks(position: .leading)
}
.chartForegroundStyleScale([
"Packages Received" : .red
])
}
}
Calendar.Component in this example is .weekday
I'm trying to create a bottom sheet in swift ui that looks something like this
https://user-images.githubusercontent.com/33900517/172068237-4dd58374-b6e6-4340-a913-7085fb64b254.mp4
My issue is that I have an animated bottom sheet, but because it is ignoring the safe area, when I click into the textfield it does not expand with the keyboard.
How would I fix this so the view expands with the keyboard but the white at the bottom still goes beyond the safe area?
I.e. the containing view should ignore the safe area, and the content within should adhere to the safe area.
Here is the bottom sheet code snippet, full example can be found here
https://gist.github.com/CTOverton/4fbfb8db2de31f3b5f5ef9ee88e8f744
var body: some View {
GeometryReader { geometry in
VStack() {
self.content
}
.padding(.vertical, 34)
.padding(.horizontal, 16)
// .frame(width: geometry.size.width, height: geometry.size.height * heightRatio, alignment: .top)
.frame(width: geometry.size.width, height: self.maxHeight, alignment: .top)
.background(Color(.white))
.cornerRadius(Constants.radius)
.frame(height: geometry.size.height, alignment: .bottom)
.offset(y: max(self.offset + self.translation, 0))
.animation(.interactiveSpring())
.gesture(
DragGesture().updating(self.$translation) { value, state, _ in
state = value.translation.height
}.onEnded { value in
let snapDistance = self.maxHeight * Constants.snapRatio
guard abs(value.translation.height) > snapDistance else {
return
}
self.isOpen = value.translation.height < 0
}
)
}
.edgesIgnoringSafeArea([.bottom, .horizontal])
.shadow(color: Color(hue: 1.0, saturation: 0.0, brightness: 0.0, opacity: 0.08), radius: 12, y: -8)
}
I've tried various configurations of .ignoreSafeArea() and .safeAreaInset() but I just can't seem to get it quite right.
Here are some pictures for reference as well
Actually instead of ignoring safe area for everything (that results in issue), we need it only in background, so the question is how to correctly construct background in this case.
Note: the .cornerRadius is also not appropriate here, because it clips content
Here is a main part of a fix. Tested with Xcode 13.4 / iOS 15.5
.background(
RoundedRectangle(cornerRadius: Constants.radius) // corners !!
.fill(.white) // background !!
.edgesIgnoringSafeArea([.bottom, .horizontal]) // << only here !!
)
Complete test module is here
I am trying to have a circle on my screen with two circles behind it in a ZStack that ease in and out with the ScaleEffect(), and change opacity. I made this in a separate SwiftUI file, where there seemed to be no issues, but once I put it in my ContentView() it this weird bug seemed to occur.
Please ignore the circles in the background, that's just my background view. But see those two circles of slightly different shades of blue? They keep entering and exiting the screen, coming behind the dark blue "plus" icon and then leaving again. Meanwhile, I'd like them to simply be behind the "plus" circle.
enter image description here
enter image description here
enter image description here
Is this because of some kind of XCode bug? Or did I write something wrong in my code?
I would really appreciate it if somebody could clarify :)
Here is my code. I made an #State private var buttonIsAnimating and defaulted it to false, and said that once the button appears, the circles should start animating. Is something wrong with the code?
ZStack {
Group {
Circle()
.fill(Color("Background2").opacity(self.buttonIsAnimating ? 0.6 : 0))
.frame(width: 75, height: 75, alignment: .center)
.scaleEffect(self.buttonIsAnimating ? 1 : 0)
Circle()
.fill(Color("Background3").opacity(self.buttonIsAnimating ? 0.7 : 0))
.frame(width: 89, height: 89, alignment: .center)
.scaleEffect(self.buttonIsAnimating ? 1 : 0)
}
.animation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true))
Button(action: {
self.showingAddANewToDoView.toggle()
}) {
Image(systemName: "plus.circle.fill")
.resizable()
.scaledToFit()
.background(Circle().fill(Color("Background")))
.foregroundColor(Color("Background4"))
.frame(width: 60, height: 60)
.padding(5)
}//: Button
.onAppear {
self.buttonIsAnimating.toggle()
}
}
Try with link animation to state, like
Group {
Circle()
.fill(Color("Background2").opacity(self.buttonIsAnimating ? 0.6 : 0))
.frame(width: 75, height: 75, alignment: .center)
.scaleEffect(self.buttonIsAnimating ? 1 : 0)
Circle()
.fill(Color("Background3").opacity(self.buttonIsAnimating ? 0.7 : 0))
.frame(width: 89, height: 89, alignment: .center)
.scaleEffect(self.buttonIsAnimating ? 1 : 0)
}
.animation(Animation.easeInOut(duration: 2).repeatForever(autoreverses: true),
value: self.buttonIsAnimating)
I would like to have a scroll view with a lot of subviews that have a custom location and can be touch-moved around by the user. They might also have some other controls in them (including text fields or even text editors). I tried the following:
struct CardThing: Identifiable {
let id: Int
let position: CGPoint
let label: String
}
let cards: [CardThing] = [
CardThing(id: 1, position: CGPoint(x: 00, y: 10), label: "Card one"),
CardThing(id: 2, position: CGPoint(x: 20, y: 20), label: "Card two"),
CardThing(id: 3, position: CGPoint(x: 40, y: 40), label: "Card three"),
CardThing(id: 4, position: CGPoint(x: 60, y: 60), label: "Card four"),
]
// The following view is a view of a graph structure.
//
struct ContentView: View {
var body: some View {
// The scroll view should be either virtually infinite
// or some auto-resizable based on content with reasonable
// margins. When margins are reached it is resized to maintain
// those margins. But that is not relevant to this question.
ScrollView {
// The content will usually be in couple of dozens or couple of hundreds
ForEach(cards) {
// Here it will be some kind of a card view in the future
Text($0.label)
// The position is explicit, should not undergo auto-layout
.position($0.position)
// Frames might also differ, should not undergo some auto-sizing
.frame(width: 320, height: 200)
.border(Color.green)
}
// The following will also be part of the view, but it is assumed
// that the answer to the original question will answer it. It is just
// here to provide more context about the idea of the view's content.
// ForEach(links) { ... display link as touchable line-like shape ... }
}
.frame(width:600, height: 400)
}
}
But the preview result looked automatically (mis-)aligned (also note the incomplete labels):
What I am doing wrong?
I'm trying to get items inside a list to line up in a specific way.
List {
HStack {
Text("1.")
Text("Item 1")
}
HStack {
Text("Item 2")
}
}
That winds up looking like this:
1. Item 1
Item 2
What I'd like is to line up, in this example, "Item 1" and "Item 2":
1. Item 1
Item 2
That is, the "item" parts all line up whether they have a list marker or not, or if they have list markers of different lengths (number 1. lines up with 100.)
I tried making a custom alignment guide as seen here but these don't seem to be respected inside a List --- it works fine if I make the AlignmentGuide and put it all in a VStack, but I need list behavior.
(I could fake this by getting rid of the HStacks and doing Text("1.\tItem 1") and Text("\tItem 2"). The tab stops would make everything line up, but I need to apply different formatting to the list marker and the list item (bolding, color, etc.), so they need to be discrete Text elements.)
Any ideas would be appreciated.
import SwiftUI
struct ContentView: View {
var body: some View {
List {
HStack {
Text("1.").frame(width: 20.0, height: nil, alignment: .leading)
Text("Item 1")
}
HStack {
Text("Item 2")
.padding(EdgeInsets(top: 0, leading: 28, bottom: 0, trailing: 0))
}
HStack {
Text("2.").frame(width: 20.0, height: nil, alignment: .leading)
Text("Item 3")
}
HStack {
Text("Item 4")
.padding(EdgeInsets(top: 0, leading: 28, bottom: 0, trailing: 0))
}
}
}
}
** Updated **
Hope this is closer to what you are looking for.
By specifying a frame around the leading value, you can control its size so it should work for your need to modify the text value.
It should also be possible to calculate values for the purpose of setting the frame and padding, but these hard coded values should achieve the immediate effect.