Xamarin.iOS UIApperance setDefaultTextAttributes

偶尔善良 提交于 2019-12-08 03:36:58

问题


I'm trying to figure out how to implement following code in Xamarin:

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

But I cannot find a way to setDefaultTextAttributes on UIApperance class.


回答1:


There are a number of missing UIAppearance features in Xamarin.iOS and in regards to your question, there is a missing API.

  • This is a bug, 🍣 I wrote my own UIAppearance.cs to add the missing features and correct the missing API and assume no other Xamarin.iOS coders really use the newer UIAppearance features as it has been broken since iOS 9 in Xamarin.

First, appearanceWhenContainedIn is deprecated and you should be using appearanceWhenContainedInInstancesOfClasses instead.

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

Second, appearanceWhenContainedInInstancesOfClasses is incorrectly defined within Xamarin.iOS as only available in tvOS and that is just not true.

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

UIAppearance.cs#L77

  • Update: I submitted a Github issue regarding this.

    • https://github.com/xamarin/xamarin-macios/issues/3230

Thus it is not available via the Xamarin.iOS wrapper API, but of course is available directly from the ObjC runtime as such:

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);

The next problem there are a number of Xamarin.iOS methods marked internal that are needed for the above code to function, so some copy/paste/modify of some source is needed:

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;
}


来源:https://stackoverflow.com/questions/48262588/xamarin-ios-uiapperance-setdefaulttextattributes

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!