cs193p_2021笔记[4]_Color_Image_Gesture

cs193p_2021_笔记_1
cs193p_2021_笔记_2
cs193p_2021_笔记_3_Animation_Transition
cs193p_2021_笔记_4_Color_Image_Gesture
cs193p_2021_笔记_5_Property Wrapper
cs193p_2021_笔记_6_Persistence
cs193p_2021_笔记_7_Document Architecture
cs193p_2021_笔记_8

--

Color, UIColor & CGColor

Color:

  • Is a color-specifier, e.g., .foregroundColor(Color.green).
  • Can also act like a ShapeStyle, e.g., .fill(Color.blue).
  • Can also act like a View, e.g., Color.white can appear wherever a View can appear.(可以当作view)

UIColor:

  • Is used to manipulate colors.(主打操控)
  • Also has many more built-in colors than Color, including “system-related” colors.(颜色更多)
  • Can be interrogated and can convert between color spaces.

For example, you can get the RGBA values from a UIColor.
Once you have desired UIColor, employ Color(uiColor:) to use it in one of the roles above.

CGColor:

  • The fundamental color representation in the Core Graphics drawing system
  • color.cgColor

Image V.S. UIImage

Image:

  • Primarily serves as a View.(主要功能是View)
  • Is not a type for vars that hold an image (i.e. a jpeg or gif or some such). That’s UIImage.
  • Access images in your Assets.xcassets (in Xcode) by name using Image(_ name: String).
  • Also, many, many system images available via Image(systemName:).
  • You can control the size of system images with .imageScale() View modifier.
  • System images also are affected by the .font modifier.
  • System images are also very useful as masks (for gradients, for example).

UIImage

  • Is the type for actually creating/manipulating images and storing in vars.
  • Very powerful representation of an image.
  • Multiple file formats, transformation primitives, animated images, etc.
  • Once you have the UIImage you want, use Image(uiImage:) to display it.

Multithreading

  • 多线程其实并不是同时运行,而是前后台非常快速地切换
  • Queue只是有顺序执行的代码,封装了threading的应用
  • 这些“代码”用closure来传递
  • main queue唯一能操作UI的线程
    • 主线程是单线程,所以不能执行异步代码
  • background queues执行任意:long-lived, non-UI tasks
    • 可以并行运行(running in parallel) -> even with main UI queue
    • 可以手动设置优先级,服务质量(QoS)等
    • 优先级永远不可能超过main queue
  • base API: GCD (Grand Central Dispatch)
    1. getting access to a queue
    2. plopping a block of code on a queue

A: Creating a Queue

There are numerous ways to create a queue, but we’re only going to look at two ...

DispatchQueue.main // the queue where all UI code must be posted
DispatchQueue.global(qos: QoS) // a non-UI queue with a certain quality of service qos (quality of service) is one of the following ...
    .userInteractive    // do this fast, the UI depends on it!
    .userInitiated  // the user just asked to do this, so do it now
    .utility    // this needs to happen, but the user didn’t just ask for it
    .background // maintenance tasks (cleanups, etc.)

B: Plopping a Closure onto a Queue

There are two basic ways to add a closure to a queue ...

let queue = DispatchQueue.main //or
let queue = DispatchQueue.global(qos:) 
queue.async { /* code to execute on queue */ }
queue.sync { /* code to execute on queue */ }

主线程里永远不要.sync, 那样会阻塞UI

DispatchQueue(global: .userInitiated).async {
    // 耗时代码
    // 不阻塞UI,也不能更新UI
    // 到主线程去更新UI
    DispatchQueue.main.async {
        // UI code can go here! we’re on the main queue! 
    }
}

Gestures

手势是iOS里的一等公民

// recognize
myView.gesture(theGesture) // theGesture must implement the Gesture protocol

// create
var theGesture: some Gesture {
    return TapGesture(count: 2)  // double tap
}

// discrete gestures
var theGesture: some Gesture {
      return TapGesture(count: 2)
        .onEnded { /* do something */ }
}

// 其实就是:
func theGesture() -> some Gesture {
    tapGesture(count: 2)
}

// “convenience versions”
myView.onTapGesture(count: Int) { /* do something */ } 
myView.onLongPressGesture(...) { /* do something */ }

// non-discrete gestures

var theGesture: some Gesture {
      DragGesture(...)
.onEnded { value in /* do something */ } 

non-discrete手势里传递的value是一个state:

  • For a DragGesture, it’s a struct with things like the start and end location of the fingers.
  • For a MagnificationGesture it’s the scale of the magnification (how far the fingers spread out).
  • For a RotationGesture it’s the Angle of the rotation (like the fingers were turning a dial).
  • 还可以跟踪一个state: @GestureState var myGestureState: MyGestureStateType = <starting value>

唯一可以更新这个myGestureState的机会:

var theGesture: some Gesture {
     DragGesture(...)
        .updating($myGestureState) { value, myGestureState, transaction in 
            myGestureState = /* usually something related to value */
        }
        .onEnded { value in /* do something */ }
 }

注意$的用法

如果不需要去计算一个gestureState传出去的话,有个updating用简版:

.onChanged { value in
/* do something with value (which is the state of the fingers) */
}

事实上,目前来看gestureState只做了两件事:

  1. 把实时手势对应的值保存起来
  2. 在手势结束时复原(对于缩放,变为1,对于移动,变为0)
  3. 同时,它是只读的,只在.updating方法里有更新的机会

所以,如果你的UI和动画逻辑,用到了手势结束时的值(即需要它复原),那么你也可以直接在.onEnded方法里手动把它设回去,等同于你也实现了你的gestureState,并且没有它那些限制。

Drag and Drop

Item Provider

  • The heart of drag nad drop is the NSItemProvider class.
  • It facilitates the transfer of data between processes (via drag and drop, for example)
  • It facilitates the transfer of a number of data types in iOS, for example:
    • NSAttributedString and NSString
    • NSURL
    • UIImage and UIColor
  • pre-Swift,所以需要bridging,比如:String as NSString

结合几个要点,一句话就能让你的元素能被拖动(drag):

Text(emoji).onDrag{ NSItemProvider(object: emoji as NSString)}

而接收(drop)则要复杂很多:

otherView.onDrop(of: [.plainText], isTarget: nil) {providers, location in return false }
  • 参接收的类型由of参数指定,这里假定是文本
  • 方法里最终要返回一个bool值,表示成功接收与否,我返了个false,意思是你能让物体拖动,但是一松开手指就复原了

itemprovider里加载对象有模板代码:

extension Array where Element == NSItemProvider {
  func loadObjects<T>(ofType theType: T.Type, firstOnly: Bool = false, using load: @escaping (T) -> Void) -> Bool where T: NSItemProviderReading {
    if let provider = first(where: { $0.canLoadObject(ofClass: theType)}) {
      provider.loadObject(ofClass: theType) { object, error in
        if let value = object as? T {
          DispatchQueue.main.async {
              load(value)
          }
        }
      }
      return true
    }
    return false
  }

// and
// where T: _ObjectiveCBridgeable, T._ObjectiveCType: NSItemProviderReading
  1. 提供了两段代码,可以看到其实就是对要加载的对象的约束不同,提供了对OC的兼容
  2. 模板代码演示了
    稳健地从拖拽对象加载内容(canload -> load)
  3. 真正的业务逻辑其实就是为拖进来的这个view选择一个位置存放(或读取它携带的数据)
  4. T.Type传的是类别的.self,比如String.self
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,128评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,316评论 3 388
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,737评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,283评论 1 287
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,384评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,458评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,467评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,251评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,688评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,980评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,155评论 1 342
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,818评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,492评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,142评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,382评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,020评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,044评论 2 352

推荐阅读更多精彩内容

  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,042评论 0 4
  • 公元:2019年11月28日19时42分农历:二零一九年 十一月 初三日 戌时干支:己亥乙亥己巳甲戌当月节气:立冬...
    石放阅读 6,877评论 0 2
  • 今天上午陪老妈看病,下午健身房跑步,晚上想想今天还没有断舍离,马上做,衣架和旁边的的布衣架,一看乱乱,又想想自己是...
    影子3623253阅读 2,909评论 1 8