c# - 如何在 Xamarin 中使用 UITextView 为 iOS 实现隐藏/显示密码样式体验?

标签 c# ios swift xamarin xamarin.ios

我知道可以使用 SecureTextEntry 属性为 UITextFields 实现密码样式效果,我还在网上找到了一些代码来实现隐藏/显示密码效果 here ,但这仅适用于 UITextFields,我需要为自定义 UITextView 实现相同的功能。我目前有一些代码可以实现为 UI 添加图像,但实际的显示/隐藏密码效果并未实现。

我在 Swift here 中找到了一些如何执行此操作的代码,但我从未使用过 Swift 并且希望熟悉 Swift 的人 可以为我将其转换为 C#,因为这可能是我需要的解决方案。

我还了解到,当 SecureTextEntry 属性设置为 true (即防止复制和转换字符成黑点),它仅在为 UITextViews 设置为 true 时阻止复制文本。这是我从这个属性 here 的文档中找到的

这是我目前在我的文件中实现显示/隐藏密码效果的代码:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using UIKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS;

[assembly: ResolutionGroupName("Xamarin")]
[assembly:ExportEffect(typeof(MyApp.iOS.CustomRenderers.PasswordEffect), "PasswordEffect")]
namespace MyApp.iOS.CustomRenderers
{
    public class PasswordEffect : PlatformEffect
    {
        protected override void OnAttached()
        {
            Configure();
        }

        protected override void OnDetached()
        {
            //do nothing
        }

        private void Configure()
        {
            if (Control != null)
            {
                if (Control is UITextView) {
                    UITextView vUpdatedEntry = (UITextView)Control;
                    var buttonRect = UIButton.FromType(UIButtonType.Custom);
                    buttonRect.SetImage(UIImage.FromBundle("eye_image"), UIControlState.Normal);
                    buttonRect.TouchUpInside += (object sender, EventArgs e1) => {
                        if (vUpdatedEntry.SecureTextEntry)
                        {
                            vUpdatedEntry.SecureTextEntry = false;
                            buttonRect.SetImage(UIImage.FromBundle("eye_crossed_image"), UIControlState.Normal);
                        }
                        else
                        {
                            vUpdatedEntry.SecureTextEntry = true;
                            buttonRect.SetImage(UIImage.FromBundle("eye_image"), UIControlState.Normal);
                        }
                    };
                    // Would love to have password effect here :)
                    vUpdatedEntry.ShouldChangeText += (textField, range, replacementString) => {
                        string text = vUpdatedEntry.Text;
                        var result = text.Substring(0, (int)range.Location) + replacementString + text.Substring((int)range.Location + (int)range.Length);
                        vUpdatedEntry.Text = result;
                        return false;
                    };

                    buttonRect.Frame = new CoreGraphics.CGRect(10.0f, 0.0f, 15.0f, 15.0f);
                    buttonRect.ContentMode = UIViewContentMode.ScaleToFill;

                    UIView paddingViewRight = new UIView(new System.Drawing.RectangleF(0.0f, 0.0f, 30.0f, 18.0f));
                    paddingViewRight.AddSubview(buttonRect);

                    buttonRect.TranslatesAutoresizingMaskIntoConstraints = false;
                    buttonRect.CenterYAnchor.ConstraintEqualTo(paddingViewRight.CenterYAnchor).Active = true;

                    vUpdatedEntry.TextContainerInset = new UIEdgeInsets(8.0f, 0.0f, 8.0f, paddingViewRight.Frame.Width+5.0f);
                    vUpdatedEntry.AddSubview(paddingViewRight);

                    paddingViewRight.TranslatesAutoresizingMaskIntoConstraints = false;
                    paddingViewRight.TrailingAnchor.ConstraintEqualTo(vUpdatedEntry.LayoutMarginsGuide.TrailingAnchor, 9.0f).Active = true;
                    paddingViewRight.HeightAnchor.ConstraintEqualTo(vUpdatedEntry.HeightAnchor).Active = true;
                    paddingViewRight.WidthAnchor.ConstraintEqualTo(buttonRect.WidthAnchor,1.0f, 0.0f).Active = true;

                    Control.Layer.CornerRadius = 4;
                    Control.Layer.BorderColor = new CoreGraphics.CGColor(255, 255, 255);
                    Control.Layer.MasksToBounds = true;
                    vUpdatedEntry.TextAlignment = UITextAlignment.Left;
                }
            }
        }

    }
}

最佳答案

你可以定义一个自定义的UITextViewDelegate来实现它。

public class TextViewDelegate : UITextViewDelegate
{
    private UITextView myTextView;
    bool secureTextViewEntry;       // default is NO
    NSMutableString secureText;
    NSTimer timer;
    NSString lastText;
    public TextViewDelegate(UITextView myTextView)
    {
        this.myTextView = myTextView; 
        secureTextViewEntry = false;
        secureText = new NSMutableString();
    }

    public override bool ShouldChangeText(UITextView textView, NSRange range, string text)
    {
        if("\n" == text)
        {
            textView.ResignFirstResponder();
            return false;
        }
        lastText = new NSString(text);
        return true;
        //return base.ShouldChangeText(textView, range, text);
    }

    public override void Changed(UITextView textView)
    {
        Console.WriteLine("-----" + secureText);
        if (secureTextViewEntry)
        {
            string text = textView.Text;
            if(text.Length > 0)
            {
                if("" == lastText)
                {
                    secureText.DeleteCharacters(new NSRange(secureText.Length - 1, 1));
                    onlyPassword();
                    if (null != timer)
                    {
                        timer.Invalidate();
                    }
                    //base.Changed(textView);
                    return;
                }
                else
                {
                    NSString one = new NSString(text.Substring(text.Length - 1));
                    secureText.Append(one);
                    NSMutableString temp = new NSMutableString();
                    for (int i = 0; i < secureText.Length - 1; i++)
                    {
                        temp.Append(new NSString("•"));
                    }
                    temp.Append(new NSString(secureText.ToString().Substring(secureText.ToString().Length - 1)));
                    myTextView.Text = temp;

                    if (null != timer)
                    {
                        timer.Invalidate();
                    }
                    timer =NSTimer.CreateScheduledTimer(2, onlyPassword);
                }
            }
            else
            {
                secureText = new NSMutableString();

            }
            //base.Changed(textView);
        }
        else {
            if (textView.Text.Length == 0)
            {
                secureText = new NSMutableString();
            }
            else
            {
                secureText = new NSMutableString();
                secureText.SetString(new NSString(textView.Text));
            }
            if(null != timer) {
                timer.Invalidate();
            }

            //base.Changed(textView);
        }
    }


    private void onlyPassword(NSTimer obj)
    {
        //throw new NotImplementedException();
        onlyPassword();
    }

    private void onlyPassword()
    {
        //throw new NotImplementedException();
        timer.Invalidate();
        NSMutableString temp = new NSMutableString();
        for(int i = 0; i< secureText.Length; i++)
        {
            temp.Append(new NSString("•"));
        }
        myTextView.Text = temp;
    }

    public override void DidChange(NSKeyValueChange changeKind, NSIndexSet indexes, NSString forKey)
    {
        base.DidChange(changeKind, indexes, forKey);
    }
    //set Secure be true or false
    public void setSecureTextViewEntry(bool _secureTextViewEntry)
    {
        secureTextViewEntry = _secureTextViewEntry;
        if (secureText.Length == 0)
        {
            return;
        }
        else
        {
            if (secureTextViewEntry)
            {
                //secret
                NSMutableString aaa = new NSMutableString();
                for (int i = 0; i < secureText.Length; i++)
                {
                    aaa.Append(new NSString("•"));
                }
                myTextView.Text = aaa;
            }else{
                //real word
                myTextView.Text = secureText;
                if (null != timer)
                {
                    timer.Invalidate();
                }
            }
        }
        Changed(myTextView);
    }

    public bool getSecureTextViewEntry()
    {
        return secureTextViewEntry;
    }
}

在 View Controller 中:

TextViewDelegate textViewDelegate;

public override void ViewDidLoad ()
{
     base.ViewDidLoad ();

     textViewDelegate = new TextViewDelegate(MyTextView);
     MyTextView.Delegate = textViewDelegate; //MyTextView from StoryBoard

}

partial void SetTrueButton_TouchUpInside(UIButton sender)
{
    textViewDelegate.setSecureTextViewEntry(true);
}

partial void SetFalseButton_TouchUpInside(UIButton sender)
{
    textViewDelegate.setSecureTextViewEntry(false);
}

效果如下:

enter image description here

注意:代码仅供引用,代码中存在一些小问题需要完善。

关于c# - 如何在 Xamarin 中使用 UITextView 为 iOS 实现隐藏/显示密码样式体验?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58208781/

相关文章:

ios - 设置图像的 UIButton 方法之间的区别

swift - 将 Swift 1 加速度计代码更新为 Swift 2 时出错

c# - NUnit with night build,如何轻松获得错误?

c# - 返回 Task<string> 的方法

ios - 从 Apple Watch 模拟器与 iPhone 设备通信

iOS 14 StoreKit - SKCloudServiceController 的 requestusertoken 未被正确调用

swift 4 : cast issue with Generics

c# - xamarin.forms 中带有附件的 ImageCell

c# - xml 用它的泛型类型序列化一个泛型类

ios - 4 个选项卡的选项卡栏 Controller 中的相同 View Controller 给出了错误的选定 tabcontroller 选定索引