Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/113.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios TextField(“,text:.常量(“测试SwiftUI TextField”)) .背景(颜色(红色:0.5,绿色:0.5,蓝色:1)) //此视图的行为类似于“SelectableText”,但布局的行为类似于“TextField”` CustomTextField(文本:。常量(“测试`CustomTextField`”) .isEditable(可编辑:false) .背景(颜色.绿色) //一个不可选择的普通文本` 文本(“测试SwiftUI`Text`”) .背景(颜色.红色) //可选择的“文本”,通过下面的按钮可以更改选择功能 SelectableText(“测试`SelectableText`可能可选”) .可选择(自选择文本) .背景(颜色.橙色) 按钮(操作:{ self.selectableText.toggle() }) { 文本(“`SelectableText`可以选择:\(self.SelectableText.description)”) } //无法更改的可选“文本” SelectableText(“测试`SelectableText`始终可选”) .背景(颜色.黄色) }.padding() } } 让viewController=UIHostingController(rootView:TextTestView()) viewController.view.frame=CGRect(x:0,y:0,宽度:400,高度:200) PlaygroundPage.current.liveView=viewController.view_Ios_Swift_Text_Swiftui - Fatal编程技术网

Ios TextField(“,text:.常量(“测试SwiftUI TextField”)) .背景(颜色(红色:0.5,绿色:0.5,蓝色:1)) //此视图的行为类似于“SelectableText”,但布局的行为类似于“TextField”` CustomTextField(文本:。常量(“测试`CustomTextField`”) .isEditable(可编辑:false) .背景(颜色.绿色) //一个不可选择的普通文本` 文本(“测试SwiftUI`Text`”) .背景(颜色.红色) //可选择的“文本”,通过下面的按钮可以更改选择功能 SelectableText(“测试`SelectableText`可能可选”) .可选择(自选择文本) .背景(颜色.橙色) 按钮(操作:{ self.selectableText.toggle() }) { 文本(“`SelectableText`可以选择:\(self.SelectableText.description)”) } //无法更改的可选“文本” SelectableText(“测试`SelectableText`始终可选”) .背景(颜色.黄色) }.padding() } } 让viewController=UIHostingController(rootView:TextTestView()) viewController.view.frame=CGRect(x:0,y:0,宽度:400,高度:200) PlaygroundPage.current.liveView=viewController.view

Ios TextField(“,text:.常量(“测试SwiftUI TextField”)) .背景(颜色(红色:0.5,绿色:0.5,蓝色:1)) //此视图的行为类似于“SelectableText”,但布局的行为类似于“TextField”` CustomTextField(文本:。常量(“测试`CustomTextField`”) .isEditable(可编辑:false) .背景(颜色.绿色) //一个不可选择的普通文本` 文本(“测试SwiftUI`Text`”) .背景(颜色.红色) //可选择的“文本”,通过下面的按钮可以更改选择功能 SelectableText(“测试`SelectableText`可能可选”) .可选择(自选择文本) .背景(颜色.橙色) 按钮(操作:{ self.selectableText.toggle() }) { 文本(“`SelectableText`可以选择:\(self.SelectableText.description)”) } //无法更改的可选“文本” SelectableText(“测试`SelectableText`始终可选”) .背景(颜色.黄色) }.padding() } } 让viewController=UIHostingController(rootView:TextTestView()) viewController.view.frame=CGRect(x:0,y:0,宽度:400,高度:200) PlaygroundPage.current.liveView=viewController.view,ios,swift,text,swiftui,Ios,Swift,Text,Swiftui,我遇到了类似的问题,本质上我希望在不允许编辑的情况下选择文本。在我的例子中,我希望在点击文本时显示UIMenuController,而不允许编辑文本或显示光标或键盘。基于先前的答案: import SwiftUI import UIKit struct SelectableText: UIViewRepresentable { var text: String @Binding var isSelected: Bool func makeUIView(context

我遇到了类似的问题,本质上我希望在不允许编辑的情况下选择文本。在我的例子中,我希望在点击文本时显示UIMenuController,而不允许编辑文本或显示光标或键盘。基于先前的答案:

import SwiftUI
import UIKit


struct SelectableText: UIViewRepresentable {
    var text: String
    @Binding var isSelected: Bool

    func makeUIView(context: Context) -> SelectableLabel {
        let label = SelectableLabel()
        label.textColor = .white
        label.font = .systemFont(ofSize: 60, weight: .light)
        label.minimumScaleFactor = 0.6
        label.adjustsFontSizeToFitWidth = true
        label.textAlignment = .right
        label.numberOfLines = 1
        label.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        label.setContentCompressionResistancePriority(.defaultLow, for: .horizontal)
        label.text = text
        return label
    }

    func updateUIView(_ uiView: SelectableLabel, context: Context) {
        uiView.text = text
        if isSelected {
            uiView.showMenu()
        } else {
            let _ = uiView.resignFirstResponder()
        }
    }
}

class SelectableLabel: UILabel {
    override var canBecomeFirstResponder: Bool {
        return true
    }

    override init(frame: CGRect) {
        super.init(frame: .zero)
        highlightedTextColor = .gray
    }

    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        switch action {
        case #selector(copy(_:)), #selector(paste(_:)), #selector(delete(_:)):
            return true
        default:
            return super.canPerformAction(action, withSender: sender)
        }
    }

    override func copy(_ sender: Any?) {
        UIPasteboard.general.string = self.stringValue
    }

    override func paste(_ sender: Any?) {
        guard let string = UIPasteboard.general.string else { return }
        NotificationCenter.default.post(name: Notification.Name.Paste, object: nil, userInfo: [Keys.PastedString: string])
    }

    override func delete(_ sender: Any?) {
        NotificationCenter.default.post(name: Notification.Name.Delete, object: nil)
    }

    override func resignFirstResponder() -> Bool {
        isHighlighted = false
        return super.resignFirstResponder()
    }

    public func showMenu() {
        becomeFirstResponder()
        isHighlighted = true
        let menu = UIMenuController.shared            
        menu.showMenu(from: self, rect: bounds)
    }
}
我使用自定义粘贴和删除通知向我的模型对象发送消息,其中粘贴和删除操作被处理以适当地更新显示,这符合我的目的。也可以使用绑定

使用:

SelectableText(text: text, isSelected: self.$isSelected)
    .onTapGesture {
         self.isSelected.toggle()
     }
     .onReceive(NotificationCenter.default.publisher(for: UIMenuController.willHideMenuNotification)) { _ in
         self.isSelected = false
     }

或者,当我们想在不允许编辑的情况下显示文本的“复制”工具提示时,也可以使用类似的方法

作为好处,我们可以使用本机视图“文本”,这使我们有机会使用本机方法“.font()”、“.foregroundColor()”等。此外,我们还可以将其用于视图组,例如示例单元格

以先前的答案为基础

操场代码

import PlaygroundSupport
import SwiftUI


/// This subclass is needed since we want to customize the cursor and the context menu
class CustomUITextField: UITextField, UITextFieldDelegate {
    
    /// Binding from the `CustomTextField` so changes of the text can be observed by `SwiftUI`
    fileprivate var _textBinding: Binding<String>!
    
    /// If it is `true` the text field behaves normally.
    /// If it is `false` the text cannot be modified only selected, copied and so on.
    fileprivate var _isEditable = true {
        didSet {
            // set the input view so the keyboard does not show up if it is edited
            self.inputView = self._isEditable ? nil : UIView()
            // do not show autocorrection if it is not editable
            self.autocorrectionType = self._isEditable ? .default : .no
        }
    }
    
    
    // change the cursor to have zero size
    override func caretRect(for position: UITextPosition) -> CGRect {
        return self._isEditable ? super.caretRect(for: position) : .zero
    }
    
    // override this method to customize the displayed items of 'UIMenuController' (the context menu when selecting text)
    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
    
        // disable 'cut', 'delete', 'paste','_promptForReplace:'
        // if it is not editable
        if (!_isEditable) {
            switch action {
            case #selector(cut(_:)),
                 #selector(delete(_:)),
                 #selector(paste(_:)):
                return false
            default:
                // do not show 'Replace...' which can also replace text
                // Note: This selector is private and may change
                if (action == Selector("_promptForReplace:")) {
                    return false
                }
            }
        }
        return super.canPerformAction(action, withSender: sender)
    }
    
    
    // === UITextFieldDelegate methods
    
    func textFieldDidChangeSelection(_ textField: UITextField) {
        // update the text of the binding
        self._textBinding.wrappedValue = textField.text ?? ""
    }
    
    func textField(_ textField: UITextField, shouldChangeCharactersIn range: NSRange, replacementString string: String) -> Bool {
        // Allow changing the text depending on `self._isEditable`
        return self._isEditable
    }
    
}

struct CustomTextField: UIViewRepresentable {
    
    @Binding private var text: String
    private var isEditable: Bool
    
    init(text: Binding<String>, isEditable: Bool = true) {
        self._text = text
        self.isEditable = isEditable
    }
    
    func makeUIView(context: UIViewRepresentableContext<CustomTextField>) -> CustomUITextField {
        let textField = CustomUITextField(frame: .zero)
        textField.delegate = textField
        textField.text = self.text
        textField.setContentHuggingPriority(.defaultHigh, for: .vertical)
        return textField
    }
    
    func updateUIView(_ uiView: CustomUITextField, context: UIViewRepresentableContext<CustomTextField>) {
        uiView.text = self.text
        uiView._textBinding = self.$text
        uiView._isEditable = self.isEditable
    }
    
    func isEditable(editable: Bool) -> CustomTextField {
        return CustomTextField(text: self.$text, isEditable: editable)
    }
}

struct SelectableText: UIViewRepresentable {
    
    private var text: String
    private var selectable: Bool
    
    init(_ text: String, selectable: Bool = true) {
        self.text = text
        self.selectable = selectable
    }
    
    func makeUIView(context: Context) -> CustomUITextField {
        let textField = CustomUITextField(frame: .zero)
        textField.delegate = textField
        textField.text = self.text
        textField.setContentHuggingPriority(.defaultHigh, for: .vertical)
        textField.setContentHuggingPriority(.defaultHigh, for: .horizontal)
        return textField
    }
    
    func updateUIView(_ uiView: CustomUITextField, context: Context) {
        uiView.text = self.text
        uiView._textBinding = .constant(self.text)
        uiView._isEditable = false
        uiView.isEnabled = self.selectable
    }
    
    func selectable(_ selectable: Bool) -> SelectableText {
        return SelectableText(self.text, selectable: selectable)
    }
    
}


struct TextTestView: View {
    
    @State private var selectableText = true
    
    var body: some View {
        VStack {
            
            // Even though the text should be constant, it is not because the user can select and e.g. 'cut' the text
            TextField("", text: .constant("Test SwiftUI TextField"))
                .background(Color(red: 0.5, green: 0.5, blue: 1))
            
            // This view behaves like the `SelectableText` however the layout behaves like a `TextField`
            CustomTextField(text: .constant("Test `CustomTextField`"))
                .isEditable(editable: false)
                .background(Color.green)
            
            // A non selectable normal `Text`
            Text("Test SwiftUI `Text`")
                .background(Color.red)
            
            // A selectable `text` where the selection ability can be changed by the button below
            SelectableText("Test `SelectableText` maybe selectable")
                .selectable(self.selectableText)
                .background(Color.orange)
            
            Button(action: {
                self.selectableText.toggle()
            }) {
                Text("`SelectableText` can be selected: \(self.selectableText.description)")
            }
            
            // A selectable `text` which cannot be changed
            SelectableText("Test `SelectableText` always selectable")
                .background(Color.yellow)
            
        }.padding()
    }
    
}

let viewController = UIHostingController(rootView: TextTestView())
viewController.view.frame = CGRect(x: 0, y: 0, width: 400, height: 200)

PlaygroundPage.current.liveView = viewController.view
import PlaygroundSupport
import SwiftUI

private class SelectableUIView: UIView {

    var text: String?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    func setup() {
        self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu)))
    }

    @objc func showMenu(_ recognizer: UILongPressGestureRecognizer) {
        becomeFirstResponder()

        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            menu.showMenu(from: self, rect: frame)
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general
        board.string = text

        UIMenuController.shared.hideMenu()
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }

}

struct SelectableView: UIViewRepresentable {

    var text: String

    func makeUIView(context: Context) -> UIView {
        let view = SelectableUIView()
        return view
    }
    func updateUIView(_ uiView: UIView, context: Context) {
        guard let view = uiView as? SelectableUIView else {
            return
        }
        view.text = text
    }
}

struct SelectableContainer<Content: View>: View {

    private let content: () -> Content
    private var text: String

    public init(text: String, @ViewBuilder content: @escaping () -> Content) {
        self.text = text
        self.content = content
    }

    public var body: some View {
        ZStack {
            content()
            SelectableView(text: text)
                .layoutPriority(-1)
        }
    }

}

struct SelectableText: View {
    private var text: String

    public init(_ text: String) {
        self.text = text
    }

    public var body: some View {
        ZStack {
            Text(text)
            SelectableView(text: text)
                .layoutPriority(-1)
        }
    }
}


struct TextTestView: View {

    @State private var text = "text"

    var body: some View {
        VStack {
            SelectableContainer(text: text) {
                VStack(alignment: .leading) {
                    Text("Header")
                        .font(.body)

                    Text(text)
                        .background(Color.orange)
                }
            }
            .background(Color.yellow)

            SelectableText(text)
                .background(Color.black)
                .foregroundColor(.white)
                .font(.largeTitle)
        }.padding()
    }

}

let viewController = UIHostingController(rootView: TextTestView())
viewController.view.frame = CGRect(x: 0, y: 0, width: 400, height: 200)

PlaygroundPage.current.liveView = viewController.view
导入PlaygroundSupport
导入快捷键
私有类SelectableUIView:UIView{
变量文本:字符串?
重写初始化(帧:CGRect){
super.init(frame:frame)
self.setup()
}
必需的初始化?(编码器aDecoder:NSCoder){
super.init(编码者:aDecoder)
self.setup()
}
函数设置(){
self.addgestureerecognizer(ui长按gestureegnizer(目标:self,操作:#选择器(self.showMenu)))
}
@objc func显示菜单(识别器:UILongPressGestureRecognitor){
成为第一响应者()
let menu=UIMenuController.shared
如果!menu.ismenu可见{
menu.showMenu(from:self,rect:frame)
}
}
覆盖函数副本(uu发送方:有吗?){
let board=UIPasteboard.general
board.string=文本
UIMenuController.shared.hideMenu()
}
覆盖变量可以成为第一响应者:Bool{
返回真值
}
覆盖功能执行(uu操作:选择器,带sender sender:Any?->Bool{
返回操作==#选择器(UIResponderStandardEditActions.copy)
}
}
结构SelectableView:UIViewRepresentable{
变量文本:字符串
func makeUIView(上下文:context)->UIView{
let view=SelectableUIView()
返回视图
}
func updateUIView(uiView:uiView,context:context){
guard let view=uiView as?SelectableUIView-else{
返回
}
view.text=文本
}
}
结构SelectableContainer:视图{
私有出租内容:()->内容
私有变量文本:字符串
公共初始化(文本:字符串,@ViewBuilder内容:@escaping()->content){
self.text=文本
self.content=内容
}
公共机构:一些看法{
ZStack{
内容()
SelectableView(文本:文本)
.布局优先级(-1)
}
}
}
结构SelectableText:视图{
私有变量文本:字符串
公共初始化(uu文本:字符串){
self.text=文本
}
公共机构:一些看法{
ZStack{
文本(文本)
SelectableView(文本:文本)
.布局优先级(-1)
}
}
}
结构文本测试视图:视图{
@State private var text=“text”
var body:一些观点{
VStack{
SelectableContainer(文本:文本){
VStack(对齐:。前导){
文本(“标题”)
.font(.body)
文本(文本)
.背景(颜色.橙色)
}
}
.背景(颜色.黄色)
可选择文本(文本)
.背景(颜色.黑色)
.foregroundColor(.白色)
.font(.largeTitle)
}.padding()
}
}
让viewController=UIHostingController(rootView:TextTestView())
viewController.view.frame=CGRect(x:0,y:0,宽度:400,高度:200)
PlaygroundPage.current.liveView=viewController.view
操场视图

我发现一个简单的解决方案是只使用上下文菜单:

Text($someText)
.contextMenu(contextMenu)(菜单项:{
按钮(“复制”,操作:{
UIPasteboard.general.string=someText
})
}))

这方面有什么更新吗?我也会对此感兴趣。也许最好依赖UITextView而不是UITextField,并从其“isEditable”属性中获益。这解决了提到的两个问题。@Unknown对于迟来的评论表示抱歉。我添加的代码不显示键盘和自动更正。您可以使用
textField.inputView=UIView()
textF
SelectableText(text: text, isSelected: self.$isSelected)
    .onTapGesture {
         self.isSelected.toggle()
     }
     .onReceive(NotificationCenter.default.publisher(for: UIMenuController.willHideMenuNotification)) { _ in
         self.isSelected = false
     }
import PlaygroundSupport
import SwiftUI

private class SelectableUIView: UIView {

    var text: String?

    override init(frame: CGRect) {
        super.init(frame: frame)
        self.setup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        self.setup()
    }

    func setup() {
        self.addGestureRecognizer(UILongPressGestureRecognizer(target: self, action: #selector(self.showMenu)))
    }

    @objc func showMenu(_ recognizer: UILongPressGestureRecognizer) {
        becomeFirstResponder()

        let menu = UIMenuController.shared
        if !menu.isMenuVisible {
            menu.showMenu(from: self, rect: frame)
        }
    }

    override func copy(_ sender: Any?) {
        let board = UIPasteboard.general
        board.string = text

        UIMenuController.shared.hideMenu()
    }

    override var canBecomeFirstResponder: Bool {
        return true
    }

    override func canPerformAction(_ action: Selector, withSender sender: Any?) -> Bool {
        return action == #selector(UIResponderStandardEditActions.copy)
    }

}

struct SelectableView: UIViewRepresentable {

    var text: String

    func makeUIView(context: Context) -> UIView {
        let view = SelectableUIView()
        return view
    }
    func updateUIView(_ uiView: UIView, context: Context) {
        guard let view = uiView as? SelectableUIView else {
            return
        }
        view.text = text
    }
}

struct SelectableContainer<Content: View>: View {

    private let content: () -> Content
    private var text: String

    public init(text: String, @ViewBuilder content: @escaping () -> Content) {
        self.text = text
        self.content = content
    }

    public var body: some View {
        ZStack {
            content()
            SelectableView(text: text)
                .layoutPriority(-1)
        }
    }

}

struct SelectableText: View {
    private var text: String

    public init(_ text: String) {
        self.text = text
    }

    public var body: some View {
        ZStack {
            Text(text)
            SelectableView(text: text)
                .layoutPriority(-1)
        }
    }
}


struct TextTestView: View {

    @State private var text = "text"

    var body: some View {
        VStack {
            SelectableContainer(text: text) {
                VStack(alignment: .leading) {
                    Text("Header")
                        .font(.body)

                    Text(text)
                        .background(Color.orange)
                }
            }
            .background(Color.yellow)

            SelectableText(text)
                .background(Color.black)
                .foregroundColor(.white)
                .font(.largeTitle)
        }.padding()
    }

}

let viewController = UIHostingController(rootView: TextTestView())
viewController.view.frame = CGRect(x: 0, y: 0, width: 400, height: 200)

PlaygroundPage.current.liveView = viewController.view