Xamarin.iOS UIApperance setDefaultTextAttributes

Xamarin.iOS UIApperance setDefaultTextAttributes

我正在尝试弄清楚如何在 Xamarin 中实现以下代码:

[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor greenColor]}];

但是我找不到在 UIApperance 上设置 DefaultTextAttributes 的方法 class。

在 Xamarin.iOS 中有 个缺失的 UIAppearance 个特征,关于你的问题,缺失 API.

  • 这是一个错误,我自己编写了 UIAppearance.cs 来添加缺失的功能并更正缺失的 API 和 假设 没有其他 Xamarin.iOS 编码人员真正使用较新的 UIAppearance 功能,因为它自 Xamarin 中的 iOS 9 以来已被破坏。

首先,appearanceWhenContainedIn 已弃用,您应该改用 appearanceWhenContainedInInstancesOfClasses

AppearanceWhenContainedIn - was deprecated in iOS 9 and is not recommended for use.

其次,appearanceWhenContainedInInstancesOfClassesXamarin.iOS 中被 错误地 定义为 仅在 tvOS 中可用 事实并非如此。

#if TVOS
   // new in iOS9 but the only option for tvOS
   const string selAppearanceWhenContainedInInstancesOfClasses = "appearanceWhenContainedInInstancesOfClasses:";
   ~~~

UIAppearance.cs#L77

因此它不能通过 Xamarin.iOS 包装器 API 使用,但当然可以直接从 ObjC 运行时使用:

var NSForegroundColorAttributeName = Dlfcn.GetStringConstant(UIKitLibraryHandle, "NSForegroundColorAttributeName");
var defaultAttributes = NSDictionary.FromObjectsAndKeys(new NSObject[] { UIColor.Red }, new NSObject[] { NSForegroundColorAttributeName });
var styleHandle = GetAppearanceEx(Class.GetHandle("UITextField"), typeof(UISearchBar));
void_objc_msgSend_IntPtr(styleHandle, Selector.GetHandle("setDefaultTextAttributes:"), defaultAttributes.Handle);

下一个问题有许多 Xamarin.iOS 标记为 internal 的方法是上述代码运行所必需的,所以一些 copy/paste/modify 一些需要来源:

public const string selAppearanceWhenContainedInInstancesOfClasses = "appearanceWhenContainedInInstancesOfClasses:";

public static readonly IntPtr UIKitLibraryHandle = Dlfcn.dlopen("/System/Library/Frameworks/UIKit.framework/UIKit", 0);

[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
public static extern IntPtr IntPtr_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

[DllImport("/usr/lib/libobjc.dylib", EntryPoint = "objc_msgSend")]
public static extern void void_objc_msgSend_IntPtr(IntPtr receiver, IntPtr selector, IntPtr arg1);

public static IntPtr GetAppearanceEx(IntPtr class_ptr, params Type[] whenFoundIn)
{
    var ptrs = TypesToPointers(whenFoundIn);
    var handles = NSArray.FromIntPtrs(ptrs);
    using (var array = handles)
    {
        return IntPtr_objc_msgSend_IntPtr(class_ptr, Selector.GetHandle(selAppearanceWhenContainedInInstancesOfClasses), array.Handle);
    }
}

public static IntPtr[] TypesToPointers(Type[] whenFoundIn)
{
    IntPtr[] ptrs = new IntPtr[whenFoundIn.Length];

    for (int i = 0; i < whenFoundIn.Length; i++)
    {
        if (whenFoundIn[i] == null)
            throw new ArgumentException(String.Format("Parameter {0} was null, must specify a valid type", i));
        if (!typeof(NSObject).IsAssignableFrom(whenFoundIn[i]))
            throw new ArgumentException(String.Format("Type {0} does not derive from NSObject", whenFoundIn[i]));

        var classHandle = Class.GetHandle(whenFoundIn[i]);
        if (classHandle == IntPtr.Zero)
            throw new ArgumentException(string.Format("Could not find the Objective-C class for {0}", whenFoundIn[i].FullName));
        ptrs[i] = classHandle;
    }
    return ptrs;
}