Xamarin.iOS UIApperance setDefaultTextAttributes

3
我正在尝试在Xamarin中实现以下代码:
[[UITextField appearanceWhenContainedIn:[UISearchBar class], nil] setDefaultTextAttributes:@{NSForegroundColorAttributeName:[UIColor greenColor]}];
但我找不到在UIApperance类上设置setDefaultTextAttributes的方法。
1个回答

4

在Xamarin.iOS中存在一些缺失的UIAppearance功能,就你的问题而言,有一个缺失的API。

  • 这是一个bug,我编写了自己的UIAppearance.cs以添加缺失的功能并修正了缺失的API,并且假设没有其他Xamarin.iOS开发人员真正使用更新的UIAppearance功能,因为它从iOS 9开始就已经损坏了。

首先,appearanceWhenContainedIn已被弃用,您应该使用appearanceWhenContainedInInstancesOfClasses代替。

AppearanceWhenContainedIn - 在iOS 9中已弃用,不建议使用。

其次,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);

enter image description here

下一个问题是有许多被标记为“internal”的Xamarin.iOS方法需要用于上述代码的功能,因此需要一些源代码的复制/粘贴/修改:
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;
}

@TunykPavel 没问题,很高兴它能帮到你。 - SushiHangover
1
哇,我一直在研究这个问题,但是一无所获,Sushi做得很好! - Iain Smith
2
@IainSmith 哈哈哈...谢谢,我有一段时间为客户编写了一个完整的 UIAppearance.cs 替代方案,然后在其上添加了一个 CSS 模板层,所以我有一个优势,即有人付钱让我学习这些技巧 ;-) - SushiHangover
抱歉我的问题晚了,但我该如何使用这段代码在UIAlertController中更改UILabel的NumberOfLInes?我需要一个两行的操作表选项... - Grupo CDS Informática
@GrupoCDSInformática 你应该提出一个新问题,说明你想要实现什么以及你目前拥有的代码。 - SushiHangover
@SushiHangover,您能给我帮个忙吗?(https://stackoverflow.com/questions/52258352/xamarin-ios-action-sheet-line-numbers) - Grupo CDS Informática

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接