美文网首页
cs193p_2021笔记[4]_Color_Image_Ges

cs193p_2021笔记[4]_Color_Image_Ges

作者: walkerwzy | 来源:发表于2021-11-07 00:17 被阅读0次

    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

    相关文章

      网友评论

          本文标题:cs193p_2021笔记[4]_Color_Image_Ges

          本文链接:https://www.haomeiwen.com/subject/kebdzltx.html