完善任务流程、键盘适配与页面交互

This commit is contained in:
2026-07-10 15:56:15 +08:00
parent f88a85a807
commit ab5220e460
189 changed files with 16779 additions and 1038 deletions

View File

@ -0,0 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>NSPrivacyAccessedAPITypes</key>
<array/>
<key>NSPrivacyTrackingDomains</key>
<array/>
<key>NSPrivacyCollectedDataTypes</key>
<array/>
<key>NSPrivacyTracking</key>
<false/>
</dict>
</plist>

View File

@ -0,0 +1,29 @@
//
// IQTextView.swift
// https://github.com/hackiftekhar/IQTextView
// Copyright (c) 2013-24 Iftekhar Qurashi.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
import IQKeyboardToolbar
@available(iOSApplicationExtension, unavailable)
@MainActor
@objc extension IQTextView: IQPlaceholderable { }

View File

@ -0,0 +1,193 @@
//
// IQTextView.swift
// https://github.com/hackiftekhar/IQTextView
// Copyright (c) 2013-24 Iftekhar Qurashi.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
import UIKit
/** @abstract UITextView with placeholder support */
@available(iOSApplicationExtension, unavailable)
@MainActor
@objcMembers open class IQTextView: UITextView {
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setup()
}
override public init(frame: CGRect, textContainer: NSTextContainer?) {
super.init(frame: frame, textContainer: textContainer)
setup()
}
override open func awakeFromNib() {
super.awakeFromNib()
setup()
}
private func setup() {
NotificationCenter.default.addObserver(self, selector: #selector(self.refreshPlaceholder),
name: UITextView.textDidChangeNotification, object: self)
do {
placeholderLabel.frame = placeholderExpectedFrame
placeholderLabel.autoresizingMask = [.flexibleWidth, .flexibleHeight]
placeholderLabel.lineBreakMode = .byWordWrapping
placeholderLabel.numberOfLines = 0
placeholderLabel.font = self.font
placeholderLabel.textAlignment = self.textAlignment
placeholderLabel.backgroundColor = UIColor.clear
placeholderLabel.isAccessibilityElement = false
placeholderLabel.textColor = UIColor.placeholderText
self.addSubview(placeholderLabel)
refreshPlaceholder()
}
}
private var placeholderInsets: UIEdgeInsets {
let top: CGFloat = self.textContainerInset.top
let left: CGFloat = self.textContainerInset.left + self.textContainer.lineFragmentPadding
let bottom: CGFloat = self.textContainerInset.bottom
let right: CGFloat = self.textContainerInset.right + self.textContainer.lineFragmentPadding
return UIEdgeInsets(top: top, left: left, bottom: bottom, right: right)
}
private var placeholderExpectedFrame: CGRect {
let insets: UIEdgeInsets = self.placeholderInsets
let maxWidth: CGFloat = self.frame.width-insets.left-insets.right
let size: CGSize = CGSize(width: maxWidth, height: self.frame.height-insets.top-insets.bottom)
let expectedSize: CGSize = placeholderLabel.sizeThatFits(size)
return CGRect(x: insets.left, y: insets.top, width: maxWidth, height: expectedSize.height)
}
public let placeholderLabel: UILabel = .init()
/** @abstract To set textView's placeholder text color. */
@IBInspectable open var placeholderTextColor: UIColor? {
get {
return placeholderLabel.textColor
}
set {
placeholderLabel.textColor = newValue
}
}
/** @abstract To set textView's placeholder text. Default is nil. */
@IBInspectable open var placeholder: String? {
get {
return placeholderLabel.text
}
set {
placeholderLabel.text = newValue
refreshPlaceholder()
}
}
/** @abstract To set textView's placeholder attributed text. Default is nil. */
open var attributedPlaceholder: NSAttributedString? {
get {
return placeholderLabel.attributedText
}
set {
placeholderLabel.attributedText = newValue
refreshPlaceholder()
}
}
open override func layoutSubviews() {
super.layoutSubviews()
placeholderLabel.frame = placeholderExpectedFrame
}
@objc private func refreshPlaceholder() {
let text: String = text ?? attributedText?.string ?? ""
placeholderLabel.alpha = text.isEmpty ? 1 : 0
}
open override var text: String! {
didSet {
refreshPlaceholder()
}
}
open override var attributedText: NSAttributedString! {
didSet {
refreshPlaceholder()
}
}
open override var font: UIFont? {
didSet {
if let font: UIFont = font {
placeholderLabel.font = font
} else {
placeholderLabel.font = UIFont.systemFont(ofSize: 12)
}
}
}
open override var textAlignment: NSTextAlignment {
didSet {
placeholderLabel.textAlignment = textAlignment
}
}
open override var intrinsicContentSize: CGSize {
guard !hasText else {
return super.intrinsicContentSize
}
var newSize: CGSize = super.intrinsicContentSize
let placeholderInsets: UIEdgeInsets = self.placeholderInsets
newSize.height = placeholderExpectedFrame.height + placeholderInsets.top + placeholderInsets.bottom
return newSize
}
open override func caretRect(for position: UITextPosition) -> CGRect {
var originalRect = super.caretRect(for: position)
// When placeholder is visible and text alignment is centered
guard placeholderLabel.alpha == 1 && self.textAlignment == .center else { return originalRect }
// Calculate the width of the placeholder text
let font = placeholderLabel.font ?? UIFont.systemFont(ofSize: UIFont.systemFontSize)
let textSize = placeholderLabel.text?.size(withAttributes: [.font: font]) ?? .zero
// Calculate the starting x position of the centered placeholder text
let centeredTextX = (self.bounds.size.width - textSize.width) / 2
// Update the caret position to match the starting x position of the centered text
originalRect.origin.x = centeredTextX
return originalRect
}
}

21
Pods/IQTextView/LICENSE generated Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2024 Mohd Iftekhar Qurashi
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

48
Pods/IQTextView/README.md generated Normal file
View File

@ -0,0 +1,48 @@
# IQTextView
[![CI Status](https://img.shields.io/travis/hackiftekhar/IQTextView.svg?style=flat)](https://travis-ci.org/hackiftekhar/IQTextView)
[![Version](https://img.shields.io/cocoapods/v/IQTextView.svg?style=flat)](https://cocoapods.org/pods/IQTextView)
[![License](https://img.shields.io/cocoapods/l/IQTextView.svg?style=flat)](https://cocoapods.org/pods/IQTextView)
[![Platform](https://img.shields.io/cocoapods/p/IQTextView.svg?style=flat)](https://cocoapods.org/pods/IQTextView)
![Screenshot](https://raw.githubusercontent.com/hackiftekhar/IQTextView/master/Screenshot/IQTextViewScreenshot.png)
## Example
To run the example project, clone the repo, and run `pod install` from the Example directory first.
## Requirements
## Installation
IQTextView is available through [CocoaPods](https://cocoapods.org). To install
it, simply add the following line to your Podfile:
```ruby
pod 'IQTextView'
```
## Usage
You can set any UITextView class to IQTextView and then you can change the placeholder and placeholderTextColor from the storyboard
To change them via code, you may have to set them programmatically
```swift
textView.placeholderTextColor = UIColor.lightGray
textView.placeholder = "Enter your message here..."
```
To work this with IQKeyboardToolbarManager to show placeholder in toolbar, you may have to confirm IQPlaceholderable manually in your code
```swift
@available(iOSApplicationExtension, unavailable)
@MainActor
extension IQTextView: IQPlaceholderable { }
```
## Author
Iftekhar Qurashi hack.iftekhar@gmail.com
## License
IQTextView is available under the MIT license. See the LICENSE file for more info.