I’ve a LandingView
that has a viewModel which is an ObservableObject. LandingView masses some CardView
s dynamically and passes a mannequin object (Binding property).
CardView
additional nests 4 totally different subviews and passes the attributes wanted by Binding. There are textual content fields in these 4 subviews. When the consumer updates the textfield knowledge, the up to date knowledge travels again to viewModel by Binding.
Now the issue is that when the consumer keys in a single character in any of these textual content fields, the viewmodel is up to date and therefore the LandingView is re-drawn which ends up in the textual content area shedding focus and consumer has to faucet on the textual content area once more.
Is there a approach to repair this? I do know that I can repair it by eliminating the Binding properties and have another mechanism to take care of knowledge movement. However, can I repair it within the present setup itself?
Thanks a lot upfront!!!!
struct LandingView: View {
@StateObject var viewModel = LandingViewModel(gridDataArray: [])
@State var identify: String = ""
var physique: some View {
let _ = Self._printChanges()
ZStack {
Shade(pink: 242/255, inexperienced: 242/255, blue: 242/255)
listView
.background(Shade.white)
.padding()
}
}
non-public var listView: some View {
ScrollView {
VStack {
ForEach(Array(viewModel.gridDataArray.enumerated()), id: .component) { index, component in
CardView(dataModel: $viewModel.gridDataArray[index])
.equatable()
}
}
}
}
}
struct CardView: View, Equatable {
static func == (lhs: CardView, rhs: CardView) -> Bool {
lhs.dataModel.hashValue == rhs.dataModel.hashValue
}
@Binding var dataModel: LandingViewDataModel
var physique: some View {
VStack(spacing: 0) {
NavyBlueView(productName: $dataModel.productName,
productId: $dataModel.productId,
productLabel: dataModel.productLabel)
YellowView(weightedProductPrice: $dataModel.weightedProductPrice,
wacSubWACUnitPrice: $dataModel.wacSubWACUnitPrice,
pvpUnitPrice: $dataModel.pvpUnitPrice)
SkyBlueView(weightedPriceUsagePercent: $dataModel.weightedPriceUsagePercent,
wacSubWACUnitPricePercent: $dataModel.wacSubWACUnitPricePercent,
pvpUnitPricePercent: $dataModel.pvpUnitPricePercent,
totalPercent: $dataModel.totalPercent)
GreenView(weightedPriceCalculated: $dataModel.weightedPriceCalculated,
wacSubWACUnitPriceCalculated: $dataModel.wacSubWACUnitPriceCalculated,
pvpUnitPriceCalculated: $dataModel.pvpUnitPriceCalculated,
totalCalculated: $dataModel.totalCalculated)
}
}
}
struct NavyBlueView: View {
@Binding var productName: String
@Binding var productId: String?
var productLabel: String
var physique: some View {
VStack(alignment: .main) {
Textual content(productLabel)
.padding()
.padding(.backside, -10)
.foregroundStyle(Shade.white)
.body(maxWidth: .infinity, alignment: .main)
HStack {
Spacer().body(width: 10)
TextField("Product Identify", textual content: $productName)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(width: 500, peak: 35)
.padding(.main, 15)
.padding(.backside, 10)
HStack {
Textual content(" ")
.body(maxWidth: .infinity)
Textual content("Weighted Value")
.body(maxWidth: .infinity)
Textual content("WAC/SubWAC Unit Value")
.body(maxWidth: .infinity)
Textual content("340B/PVP Unit Value")
.body(maxWidth: .infinity)
Textual content("Complete")
.body(maxWidth: .infinity)
}
.foregroundStyle(Shade.white)
.padding(.backside, 10)
}
.background(Shade(pink: 41 / 255, inexperienced: 78 / 255, blue: 124 / 255))
.clipShape(.rect(
topLeadingRadius: 10,
bottomLeadingRadius: 0,
bottomTrailingRadius: 0,
topTrailingRadius: 10)
)
.padding(.horizontal)
}
}
struct YellowView: View {
@Binding var weightedProductPrice: String
@Binding var wacSubWACUnitPrice: String
@Binding var pvpUnitPrice: String
var physique: some View {
HStack {
Group {
Textual content("Product Value")
HStack {
Spacer().body(width: 10)
TextField("Product worth", textual content: $weightedProductPrice)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
HStack {
Spacer().body(width: 10)
TextField("Product worth", textual content: $wacSubWACUnitPrice)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
.padding(10)
HStack {
Spacer().body(width: 10)
TextField("Product worth", textual content: $pvpUnitPrice)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
Textual content("")
.body(maxWidth: .infinity)
.body(peak: 35)
.padding(10)
.background(Shade(pink: 238/255, inexperienced: 238/255, blue: 239/255))
}
.body(maxWidth: .infinity)
}
.body(maxWidth: .infinity)
.background(Shade(pink: 255/255, inexperienced: 254/255, blue: 185/255))
.padding(.horizontal)
}
}
struct SkyBlueView: View {
@Binding var weightedPriceUsagePercent: String
@Binding var wacSubWACUnitPricePercent: String
@Binding var pvpUnitPricePercent: String
@Binding var totalPercent: String
var physique: some View {
HStack {
Group {
Textual content("Utilization %")
HStack {
Spacer().body(width: 10)
TextField("Proportion", textual content: $weightedPriceUsagePercent)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
HStack {
Spacer().body(width: 10)
TextField("Proportion", textual content: $wacSubWACUnitPricePercent)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
.padding(10)
HStack {
Spacer().body(width: 10)
TextField("Proportion", textual content: $pvpUnitPricePercent)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
ZStack {
HStack {
Spacer().body(width: 10)
TextField("", textual content: $totalPercent)
.textFieldStyle(.plain)
.body(maxWidth: .infinity, maxHeight: .infinity)
}
.background(Rectangle().fill(Shade.white))
.body(peak: 35)
.border((Shade(pink: 183/255, inexperienced: 181/255, blue: 182/255)), width: 2)
.padding(10)
}
.body(maxWidth: .infinity)
.body(peak: 35)
.padding(10)
.background(Shade(pink: 238/255, inexperienced: 238/255, blue: 239/255))
}
.body(maxWidth: .infinity)
}
.body(maxWidth: .infinity)
.background(Shade(pink: 199/255, inexperienced: 229/255, blue: 243/255))
.padding(.horizontal)
}
}
struct GreenView: View {
@Binding var weightedPriceCalculated: String
@Binding var wacSubWACUnitPriceCalculated: String
@Binding var pvpUnitPriceCalculated: String
@Binding var totalCalculated: String
var physique: some View {
HStack {
Group {
Textual content("Weighted Value")
.body(maxWidth: .infinity)
Textual content(weightedPriceCalculated)
.body(maxWidth: .infinity)
Textual content(wacSubWACUnitPriceCalculated)
.body(maxWidth: .infinity)
Textual content(pvpUnitPriceCalculated)
.body(maxWidth: .infinity)
ZStack {
Textual content(totalCalculated)
.body(maxWidth: .infinity)
}
.body(maxWidth: .infinity)
.body(peak: 25)
.padding(10)
.background(Shade(pink: 76/255, inexperienced: 174/255, blue: 234/255))
}
.body(maxWidth: .infinity)
}
.body(maxWidth: .infinity)
.background(Shade(pink: 195/255, inexperienced: 231/255, blue: 145/255))
.padding(.horizontal)
}
}
remaining class LandingViewModel: ObservableObject {
@Printed var gridDataArray: [LandingViewDataModel] = []
init(gridDataArray: [LandingViewDataModel]) {
self.gridDataArray = gridDataArray
self.gridDataArray.append(LandingViewDataModel(productLabel: "Endo Product",
productName: "Endo product one thing",
productId: "Endo product ID",
weightedProductPrice: "122.43",
weightedPriceUsagePercent: "30",
weightedPriceCalculated: "",
wacSubWACUnitPrice: "111.33",
wacSubWACUnitPricePercent: "20",
wacSubWACUnitPriceCalculated: "",
pvpUnitPrice: "222.33",
pvpUnitPricePercent: "50",
pvpUnitPriceCalculated: "",
totalPercent: "",
totalCalculated: ""))
self.gridDataArray.append(LandingViewDataModel(productLabel: "Competitor 1",
productName: "Competitor 1",
productId: nil,
weightedProductPrice: "198.43",
weightedPriceUsagePercent: "10",
weightedPriceCalculated: "",
wacSubWACUnitPrice: "987.33",
wacSubWACUnitPricePercent: "70",
wacSubWACUnitPriceCalculated: "",
pvpUnitPrice: "876.33",
pvpUnitPricePercent: "20",
pvpUnitPriceCalculated: "",
totalPercent: "",
totalCalculated: ""))
self.gridDataArray.append(LandingViewDataModel(productLabel: "Competitor 2",
productName: "Competitor 2",
productId: nil,
weightedProductPrice: "445.43",
weightedPriceUsagePercent: "40",
weightedPriceCalculated: "",
wacSubWACUnitPrice: "432.33",
wacSubWACUnitPricePercent: "20",
wacSubWACUnitPriceCalculated: "",
pvpUnitPrice: "456.33",
pvpUnitPricePercent: "40",
pvpUnitPriceCalculated: "",
totalPercent: "",
totalCalculated: ""))
}
}
struct LandingViewDataModel: Hashable, Equatable {
let productLabel: String
var productName: String
var productId: String?
var weightedProductPrice: String {
didSet {
calculate()
}
}
var weightedPriceUsagePercent: String {
didSet {
calculate()
}
}
var weightedPriceCalculated: String
var wacSubWACUnitPrice: String {
didSet {
calculate()
}
}
var wacSubWACUnitPricePercent: String {
didSet {
calculate()
}
}
var wacSubWACUnitPriceCalculated: String
var pvpUnitPrice: String {
didSet {
calculate()
}
}
var pvpUnitPricePercent: String {
didSet {
calculate()
}
}
var pvpUnitPriceCalculated: String
var totalPercent: String
var totalCalculated: String
}
extension LandingViewDataModel {
non-public mutating func calculate() {
if let flotPrice = Float(weightedProductPrice), let proportion = Float(weightedPriceUsagePercent) {
weightedPriceCalculated = "(flotPrice * (proportion / 100))"
}
if let flotPrice = Float(wacSubWACUnitPrice), let proportion = Float(wacSubWACUnitPricePercent) {
wacSubWACUnitPriceCalculated = "(flotPrice * (proportion / 100))"
}
if let flotPrice = Float(pvpUnitPrice), let proportion = Float(pvpUnitPricePercent) {
pvpUnitPriceCalculated = "(flotPrice * (proportion / 100))"
}
if let weightedPriceUsagePercent = Int(weightedPriceUsagePercent),
let wacSubWACUnitPricePercent = Int(wacSubWACUnitPricePercent),
let pvpUnitPricePercent = Int(pvpUnitPricePercent) {
totalPercent = "(weightedPriceUsagePercent + wacSubWACUnitPricePercent + pvpUnitPricePercent)"
}
if let weightedPriceCalculated = Float(weightedPriceCalculated),
let wacSubWACUnitPriceCalculated = Float(wacSubWACUnitPriceCalculated),
let pvpUnitPriceCalculated = Float(pvpUnitPriceCalculated) {
totalCalculated = "(weightedPriceCalculated + wacSubWACUnitPriceCalculated + pvpUnitPriceCalculated)"
}
}
}