我如何在 Swift 5 中使用协议函数参数使用相关类型的协议即 .pickerStyle()

问题描述

我正在使用 SwiftUI 并希望根据选择器中的项目数量设置视图的选择器样式。对于少数项目,SegmentedPickerStyle() 是理想的,WheelPickerStyle() 越多越好。

library(tidyverse)
library(dplyr)
library(ggplot2)
library(gganimate)
library(ggstance)
library(zoo)
library(gifski)
library(shadowtext)

stats <- read_csv(url("https://raw.githubusercontent.com/samhoppen/Fantasy-Evaluator/main/Data/Animation%20Test%20Data.csv")) %>% 
  mutate(unique_id = paste0(player_name,recent_team))
all_weeks <- read_csv(url("https://raw.githubusercontent.com/samhoppen/Fantasy-Evaluator/main/Data/Animation%20Weeks%20Data.csv"))

NFL_pri <- stats$team_color
names(NFL_pri) <- stats$unique_id
NFL_sec <- stats$team_color2
names(NFL_sec) <- stats$unique_id

rb_ani <- ggplot(data = stats,aes(group = player_name)) +
  geom_colh(aes(x = tot_fpts,y = rank,color = unique_id,fill = unique_id),position = 'identity',size = 2,width = 0.8) + 
  scale_x_continuous(expand = expansion(mult = c(0,0.05))) +
  scale_y_reverse(expand = expansion(mult = c(0.01,0.01)))+
  geom_shadowtext(aes(x = name_loc,label = player_name,color = unique_id),bg.color = 'white',size = 5.5,na.rm = T,bg.r = 0.075,show.legend = FALSE) +
  scale_color_manual(values = NFL_sec)+
  scale_fill_manual(values = NFL_pri)+ 
  labs(title = "Highest-scoring Fantasy Running Backs of the Past Decade",subtitle = paste0("{all_weeks$week_name[as.numeric(previous_state)]}"),caption = "Figure: @SamHoppen | Data: @nflfastR",y = "",x = "Total Fantasy Points")+
  theme(legend.position = "none",plot.title = element_text(size = 24,face = "bold",margin = margin(0,10,0)),plot.subtitle = element_text(size = 12,plot.caption = element_text(size = 12)) +
  transition_states(states = week_order,transition_length = 2,state_length = 1,wrap = F) +
  view_follow(fixed_y = TRUE) +
  enter_fly(y_loc = -21) +
  exit_fly(y_loc = -21) +
  ease_aes('linear')

anim <- animate(rb_ani,nframes = 100,fps = 5,renderer = gifski_renderer(),height = 900,width = 1600)

函数签名如下: 我学到的 }.pickerStyle(productsObserver.product.productFamilies?.count ?? 0 < 5 ? SegmentedPickerStyle() : WheelPickerStyle()) 在函数签名中使用泛型,因为 PickerStyle 使用关联类型。

问题不应该那么难,可能也不是 - 协议应该像这样简单 = 一样工作,但我看不到它。 非常感谢任何帮助!

解决方法

pickerStyle 是一种通用方法,它接受符合 PickerStyle 的具体类型(在编译时)。因此,它不能是 SegmentedPickerStyleWheelPickerStyle(在运行时确定)——它必须是其中之一。

因此,一个建议是创建一个视图修饰符并有条件地应用选择器样式。这里的关键区别在于它返回 _ConditionalContent<TrueContent,FalseContent> 类型的条件视图。

struct PickerStyleOption<P1: PickerStyle,P2: PickerStyle>: ViewModifier {
    let predicate: () -> Bool
    let style1: P1
    let style2: P2
    
    @ViewBuilder
    func body(content: Content) -> some View {
        if predicate() {
            content
                .pickerStyle(style1)
        } else {
            content
                .pickerStyle(style2)
        }
    }
}

为方便起见,您可以创建一个扩展:

extension View {
    func pickerStyleOption<P1: PickerStyle,P2: PickerStyle>(
            _ condition: @autoclosure @escaping () -> Bool,then style1: P1,else style2: P2) -> some View {

        self.modifier(
            PickerStyleOption(predicate: condition,style1: style1,style2: style2)
        )
    }
}

并像这样使用它:

Picker(...) {
   ...
}
.pickerStyleOption((productsObserver.product.productFamilies?.count ?? 0) < 5,then: SegmentedPickerStyle(),else: WheelPickerStyle())

相关问答

错误1:Request method ‘DELETE‘ not supported 错误还原:...
错误1:启动docker镜像时报错:Error response from daemon:...
错误1:private field ‘xxx‘ is never assigned 按Alt...
报错如下,通过源不能下载,最后警告pip需升级版本 Requirem...