简体   繁体   中英

Problem when rendering Android.Xamarin layout with custom text view in VS2019

I've created some custom elements such as a CustomTextView, so I can change at desire some visual styles such as fontsize, font family etc. This is the code for my CustomTextView:

using System;
using Android.Content;
using Android.Graphics;
using Android.Runtime;
using Android.Util;
using Android.Widget;
using myapp.Core;
using myapp.Models;

namespace myapp.Views.CustomControls
{
    public class TextViewCustom : TextView
    {
        private Color color;
        private Typeface customFont;
        private CUSTOM_FONTS_SIZE textSize;
        
        protected TextViewCustom(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
        {
        }

        public TextViewCustom(Context context) : base(context)
        {
            Initialize(context);
        }

        public TextViewCustom(Context context, IAttributeSet attrs) : base(context, attrs)
        {
            Initialize(context, attrs);
        }

        private void Initialize(Context context, IAttributeSet attrs = null)
        {
            color = AppearanceManager.ColorPrimary;
            customFont = AppearanceManager.Typeface;
            textSize = CUSTOM_FONTS_SIZE.SMALL;

            int textType = 0;
            int colorType = 0;
            if (attrs != null)
            {
                var array = context.ObtainStyledAttributes(attrs, Resource.Styleable.text_view_custom, 0, 0);
                colorType = array.GetInt(Resource.Styleable.text_view_custom_tvc_color, colorType);
                textType = array.GetInt(Resource.Styleable.text_view_custom_tvc_type, textType);
                array.Recycle();
            }
            
            switch (colorType)
            {
                case 1: color = AppearanceManager.ColorPrimary;
                    break;
                case 2: color = AppearanceManager.ColorSecundary;
                    break;
                default: colorType = 0;
                    break;
            }
            
            switch (textType)
            {
                case 1: textSize = CUSTOM_FONTS_SIZE.SMALL;
                    break;
                case 2: textSize = CUSTOM_FONTS_SIZE.MIDDLE;
                    break;
                case 3: textSize = CUSTOM_FONTS_SIZE.LARGE;
                    break;
                case 4: textSize = CUSTOM_FONTS_SIZE.TINY;
                    break;
            }
            
            if(colorType > 0) SetTextColor(color);
            SetTypeface(customFont, TypefaceStyle.Normal);
            SetTextSize(ComplexUnitType.Px, AppearanceManager.TypefaceSize(textSize));
        }
    }
}

, this

using System;
using Android.Graphics;
using myapp.Core;

namespace myapp.Models
{
    public enum CUSTOM_FONTS_STYLE { DEFAULT,  SEGOE_UI, BUBLE_JELLY_SHADOW, AUGUSTA,  VCR_OSD_MONO, SWEET_PURPLE}
    public enum CUSTOM_FONTS_SIZE { SMALL, MIDDLE, LARGE, TINY }

    public class AppearanceInfo
    {
        public Color? ColorPrimary { get; set; }
        public Color? ColorPrimaryDark  { get; set; }
        public Color? ColorPrimaryText  { get; set; }
        public Color? ColorSecundary { get; set; }
        public Color? ColorSecundaryDark { get; set; }
        public Color? ColorSecundaryText { get; set; }
        
        public CUSTOM_FONTS_STYLE CustomFont { get; set; }

        public void SetColorPrimaryFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorPrimary = Color.ParseColor(hexColor);
        }

        public void SetColorPrimaryDarkFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorPrimaryDark = Color.ParseColor(hexColor);
        }

        public void SetColorPrimaryTextFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorPrimaryText = Color.ParseColor(hexColor);
        }

        public void SetColorSecundaryFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorSecundary = Color.ParseColor(hexColor);
        }

        public void SetColorSecundaryDarkFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorSecundaryDark = Color.ParseColor(hexColor);
        }

        public void SetColorSecundaryTextFromHex(string hexColor)
        {
            if (hexColor.IndexOf("#", StringComparison.Ordinal) != 0) hexColor = $"#{hexColor}";
            if (!Utils.IsValidHexColor(hexColor)) return;
            ColorSecundaryText = Color.ParseColor(hexColor);
        }
    }
}

and finally this:

using Android.Graphics;
using myapp.Models;

namespace myapp.Core
{
    public enum APPEARANCES_TEMPORAL { DEFAULT, MEDIEVAL, GAMER, MODERN, CHILDREN, CUTE }
    
    public static class AppearanceManager
    {
        private static AppearanceInfo _customAppearance;

        public static Color ColorPrimary { get; private set; }
        public static Color ColorPrimaryDark  { get; private set; }
        public static Color ColorPrimaryText  { get; private set; }
        public static Color ColorSecundary { get; private set; }
        
        public static Color ColorSecundaryDark { get; private set; }
        
        public static Color ColorSecundaryText { get; private set; }

        public static Typeface Typeface
        {
            get
            {
                if (_customAppearance == null || _customAppearance.CustomFont == CUSTOM_FONTS_STYLE.DEFAULT) 
                    return Typeface.Default;
                
                switch (_customAppearance.CustomFont)
                {
                    case CUSTOM_FONTS_STYLE.SEGOE_UI:
                        return LocalResourceProvider.GetFont(Resource.Font.segoe_ui);
                    case CUSTOM_FONTS_STYLE.BUBLE_JELLY_SHADOW:
                        return LocalResourceProvider.GetFont(Resource.Font.buble_jelly_shadow);
                    case CUSTOM_FONTS_STYLE.VCR_OSD_MONO:
                        return LocalResourceProvider.GetFont(Resource.Font.vcr_osd_mono);
                    case CUSTOM_FONTS_STYLE.AUGUSTA:
                        return LocalResourceProvider.GetFont(Resource.Font.augusta);
                    case CUSTOM_FONTS_STYLE.SWEET_PURPLE:
                        return LocalResourceProvider.GetFont(Resource.Font.sweet_purple);
                    default:
                        return Typeface.Default;
                }
            }
        }

        public static float TypefaceSize(CUSTOM_FONTS_SIZE size)
        {
            float tinySize = LocalResourceProvider.GetDimension(Resource.Dimension.textTiny);
            float smallSize = LocalResourceProvider.GetDimension(Resource.Dimension.textSmall);
            float middleSize = LocalResourceProvider.GetDimension(Resource.Dimension.textMiddle);
            float largeSize = LocalResourceProvider.GetDimension(Resource.Dimension.textLarge);

            if (_customAppearance != null)
            {
                if (_customAppearance.CustomFont == CUSTOM_FONTS_STYLE.SWEET_PURPLE)
                {
                    tinySize = LocalResourceProvider.SpToPx(17);
                    smallSize = LocalResourceProvider.SpToPx(20);
                    middleSize = LocalResourceProvider.SpToPx(25);
                    largeSize = LocalResourceProvider.SpToPx(30);
                }
                //ADD MORE CUSTOM SIZES WHEN NECESSARY
            }
            
            if (size == CUSTOM_FONTS_SIZE.TINY) return tinySize;
            if (size == CUSTOM_FONTS_SIZE.SMALL) return smallSize;
            if (size == CUSTOM_FONTS_SIZE.MIDDLE) return middleSize;
            if (size == CUSTOM_FONTS_SIZE.LARGE) return largeSize;
            return smallSize;
        }

        public static void LoadDefaultAppearance()
        {
            ColorPrimary = LocalResourceProvider.GetColor(Resource.Color.primary);
            ColorPrimaryDark = LocalResourceProvider.GetColor(Resource.Color.primaryDark);
            ColorSecundary = LocalResourceProvider.GetColor(Resource.Color.secundary);
            ColorSecundaryDark = LocalResourceProvider.GetColor(Resource.Color.secundaryDark);
            ColorPrimaryText = Color.White;
            ColorSecundaryText = Color.White;
            _customAppearance = null;
        }
        
        public static void LoadCustomAppearance(AppearanceInfo customAppearance)
        {
            LoadDefaultAppearance();
            if (customAppearance == null) return;

            _customAppearance = customAppearance;

            ColorPrimary = _customAppearance.ColorPrimary ?? ColorPrimary;
            ColorPrimaryDark = _customAppearance.ColorPrimaryDark ?? ColorPrimaryDark;
            ColorPrimaryText = _customAppearance.ColorPrimaryText ?? ColorPrimaryText;
            ColorSecundary = _customAppearance.ColorSecundary ?? ColorSecundary;
            ColorSecundaryDark = _customAppearance.ColorSecundaryDark ?? ColorSecundaryDark;
            ColorSecundaryText = _customAppearance.ColorSecundaryText ?? ColorSecundaryText;
        }

        public static void SetAppearanceTemporal(APPEARANCES_TEMPORAL appearanceType)
        {
            switch (appearanceType)
            {
                case APPEARANCES_TEMPORAL.MEDIEVAL:
                    AppearanceInfo MedievalAppearance = new AppearanceInfo();
                    MedievalAppearance.SetColorPrimaryFromHex("5d4037");
                    MedievalAppearance.SetColorPrimaryDarkFromHex("3e2723");
                    MedievalAppearance.SetColorPrimaryTextFromHex("ffd54f");
                    MedievalAppearance.SetColorSecundaryFromHex("607d8b");
                    MedievalAppearance.SetColorSecundaryDarkFromHex("455a64");
                    MedievalAppearance.CustomFont = CUSTOM_FONTS_STYLE.AUGUSTA;
                    LoadCustomAppearance(MedievalAppearance);
                    break;
                case APPEARANCES_TEMPORAL.GAMER:
                    AppearanceInfo GamerAppearance = new AppearanceInfo();
                    GamerAppearance.SetColorPrimaryFromHex("212121");
                    GamerAppearance.SetColorPrimaryDarkFromHex("212121");
                    GamerAppearance.SetColorPrimaryTextFromHex("ffff00");
                    GamerAppearance.SetColorSecundaryFromHex("212121");
                    GamerAppearance.SetColorSecundaryDarkFromHex("212121");
                    GamerAppearance.CustomFont = CUSTOM_FONTS_STYLE.VCR_OSD_MONO;
                    LoadCustomAppearance(GamerAppearance);
                    break;
                case APPEARANCES_TEMPORAL.MODERN:
                    AppearanceInfo ModernAppearance = new AppearanceInfo();
                    ModernAppearance.SetColorPrimaryFromHex("78909c");
                    ModernAppearance.SetColorPrimaryDarkFromHex("546e7a");
                    ModernAppearance.SetColorSecundaryFromHex("00796b");
                    ModernAppearance.SetColorSecundaryDarkFromHex("004d40");
                    ModernAppearance.CustomFont = CUSTOM_FONTS_STYLE.SEGOE_UI;
                    LoadCustomAppearance(ModernAppearance);
                    break;
                case APPEARANCES_TEMPORAL.CHILDREN:
                    AppearanceInfo ChildrenAppearance = new AppearanceInfo();
                    ChildrenAppearance.SetColorPrimaryFromHex("2196f3");
                    ChildrenAppearance.SetColorPrimaryDarkFromHex("1976d2");
                    ChildrenAppearance.SetColorPrimaryTextFromHex("ffea00");
                    ChildrenAppearance.SetColorSecundaryFromHex("4caf50");
                    ChildrenAppearance.SetColorSecundaryDarkFromHex("388e3c");
                    ChildrenAppearance.CustomFont = CUSTOM_FONTS_STYLE.BUBLE_JELLY_SHADOW;
                    LoadCustomAppearance(ChildrenAppearance);
                    break;
                case APPEARANCES_TEMPORAL.CUTE:
                    AppearanceInfo CuteAppearance = new AppearanceInfo();
                    CuteAppearance.SetColorPrimaryFromHex("c2185b");
                    CuteAppearance.SetColorPrimaryDarkFromHex("880e4f");
                    CuteAppearance.SetColorSecundaryFromHex("ba68c8");
                    CuteAppearance.SetColorSecundaryDarkFromHex("9c27b0");
                    CuteAppearance.CustomFont = CUSTOM_FONTS_STYLE.SWEET_PURPLE;
                    LoadCustomAppearance(CuteAppearance);
                    break;
                default:
                    LoadDefaultAppearance();
                    break;
            }
        }
    }
}

But when I use one of this CustomTextView and want to see it rendering the layout at VS2019, I',m prompted this error:

使用 CustomTextView 渲染布局时出错

Any ideas about it?

Regards

The error says it all. You have a NullReferenceException in your code. Set a break-point and narrow it down to where it happens.

But it looks like it happens in AppearanceManager.TypefaceSize . It is unclear to me what LocalResourceProvider is, but it likely requires a context to convert the dimensions, which throws a NullReferenceException.

You have the debugger, set some appropriate break points and debug your code. The relevant failing code is not in your question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM