创建自定义视图时出现错误

时间:2019-06-03 13:30:02

标签: android xamarin.android

为微光布局创建自定义视图时出错。 参考:https://github.com/team-supercharge/ShimmerLayout/blob/master/shimmerlayout/src/main/java/io/supercharge/shimmerlayout/ShimmerLayout.java

错误:System.NotSupportedException:无法将Java类型'md5f5fa8eda1f5ef6033c7dd372483fe62e / ShimmerSplitsLayout'的Java类型的JNI句柄0xbeb6ade8(key_handle 0xbc32e58)激活为托管类型'JammberSplits.Droid.CustomControls。。

  internal class ViewTreeObserverListner : Java.Lang.Object, ViewTreeObserver.IOnPreDrawListener
{
    ViewTreeObserver _viewTreeObserver;
    ShimmerSplitsLayout _shimmerLayout;
    public ViewTreeObserverListner(ViewTreeObserver viewTreeObserver, ShimmerSplitsLayout shimmerLayout)
    {
        _viewTreeObserver = viewTreeObserver;
        _shimmerLayout = shimmerLayout;
    }

    public bool OnPreDraw()
    {
        _viewTreeObserver.RemoveOnPreDrawListener(this);
        //_shimmerLayout.startShimmerAnimation();
        return true;
    }
}

internal class ShimmerAnimation : Java.Lang.Object, ValueAnimator.IAnimatorUpdateListener
{
    int _animationFromX;
    public ShimmerAnimation(int animationFromX)
    {
        _animationFromX = animationFromX;
    }

    public void OnAnimationUpdate(ValueAnimator animation)
    {
         ShimmerSplitsLayout.maskOffsetX = _animationFromX + (int)animation.AnimatedValue;
    }
}

public class ShimmerSplitsLayout : FrameLayout
{
    private static int DEFAULT_ANIMATION_DURATION = 1500;

    private static byte DEFAULT_ANGLE = 20;

    private static byte MIN_ANGLE_VALUE = Convert.ToByte(-45);
    private static byte MAX_ANGLE_VALUE = 45;
    private static byte MIN_MASK_WIDTH_VALUE = 0;
    private static byte MAX_MASK_WIDTH_VALUE = 1;

    private static byte MIN_GRADIENT_CENTER_COLOR_WIDTH_VALUE = 0;
    private static byte MAX_GRADIENT_CENTER_COLOR_WIDTH_VALUE = 1;


    public static int maskOffsetX;
    private Rect maskRect;
    private Paint gradientTexturePaint;
    private ValueAnimator maskAnimator;

    private Bitmap localMaskBitmap;
    private Bitmap maskBitmap;
    private Canvas canvasForShimmerMask;

    private bool isAnimationReversed;
    private bool isAnimationStarted;
    private bool autoStart;
    private int shimmerAnimationDuration;
    private int shimmerColor;
    private int shimmerAngle;
    private float maskWidth;
    private float gradientCenterColorWidth;
    private ViewTreeObserver.IOnPreDrawListener startAnimationPreDrawListener;


    public ShimmerSplitsLayout(Context context) : base(context)
    {
    }

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

    public ShimmerSplitsLayout(Context context, IAttributeSet attrs, int defStyleAttr) : base(context, attrs, defStyleAttr)
    {
        Initialize(context, attrs);
    }

    public ShimmerSplitsLayout(Context context, IAttributeSet attrs, int defStyleAttr, int defStyleRes) : base(context, attrs, defStyleAttr, defStyleRes)
    {
        Initialize(context, attrs);
    }

    protected ShimmerSplitsLayout(IntPtr javaReference, JniHandleOwnership transfer) : base(javaReference, transfer)
    {
    }

    private void Initialize(Context context, IAttributeSet attrs)
    {
                    SetWillNotDraw(false);

        TypedArray a = context.Theme.ObtainStyledAttributes(
                attrs,
                Resource.Styleable.ShimmerLayout,
                0, 0);

        try
        {
            shimmerAngle = a.GetInteger(Resource.Styleable.ShimmerLayout_shimmer_angle, DEFAULT_ANGLE);
            shimmerAnimationDuration = a.GetInteger(Resource.Styleable.ShimmerLayout_shimmer_animation_duration, DEFAULT_ANIMATION_DURATION);

            shimmerColor = a.GetColor(Resource.Styleable.ShimmerLayout_shimmer_color, Resources.GetColor(Resource.Color.shimmer_color));
            autoStart = a.GetBoolean(Resource.Styleable.ShimmerLayout_shimmer_auto_start, false);
            maskWidth = a.GetFloat(Resource.Styleable.ShimmerLayout_shimmer_mask_width, 0.5F);
            gradientCenterColorWidth = a.GetFloat(Resource.Styleable.ShimmerLayout_shimmer_gradient_center_color_width, 0.1F);
            isAnimationReversed = a.GetBoolean(Resource.Styleable.ShimmerLayout_shimmer_reverse_animation, false);
        }
        finally
        {
            a.Recycle();
        }

        setMaskWidth(maskWidth);
        setGradientCenterColorWidth(gradientCenterColorWidth);
        setShimmerAngle(shimmerAngle);

        enableForcedSoftwareLayerIfNeeded();

        if (autoStart && Visibility == ViewStates.Visible)
        {
            startShimmerAnimation();
        }
    }

     protected override void OnDetachedFromWindow()
     {
         resetShimmering();
         base.OnDetachedFromWindow();
     }

     private void resetIfStarted()
     {
         if (isAnimationStarted)
         {
             resetShimmering();
             startShimmerAnimation();
         }
     }

     protected override void DispatchDraw(Canvas canvas)
     {
         if (!isAnimationStarted || Width <= 0 || Height <= 0)
         {
             base.DispatchDraw(canvas);
         }
         else
         {
             dispatchDrawShimmer(canvas);
         }

     }



     private void dispatchDrawShimmer(Canvas canvas)
     {
         localMaskBitmap = getMaskBitmap();
         if (localMaskBitmap == null)
         {
             return;
         }

         if (canvasForShimmerMask == null)
         {
             canvasForShimmerMask = new Canvas(localMaskBitmap);
         }

         canvasForShimmerMask.DrawColor(Color.Transparent, PorterDuff.Mode.Clear);

         canvasForShimmerMask.Save();
         canvasForShimmerMask.Translate(-maskOffsetX, 0);

         base.DispatchDraw(canvasForShimmerMask);

         canvasForShimmerMask.Restore();

         drawShimmer(canvas);

         localMaskBitmap = null;
     }

     private void resetShimmering()
     {
         if (maskAnimator != null)
         {
             maskAnimator.End();
             maskAnimator.RemoveAllUpdateListeners();
         }

         maskAnimator = null;
         gradientTexturePaint = null;
         isAnimationStarted = false;

         releaseBitMaps();
     }

     private void drawShimmer(Canvas destinationCanvas)
     {
         createShimmerPaint();

         destinationCanvas.Save();

         destinationCanvas.Translate(maskOffsetX, 0);
         destinationCanvas.DrawRect(maskRect.Left, 0, maskRect.Width(), maskRect.Height(), gradientTexturePaint);

         destinationCanvas.Restore();
     }


     public void startShimmerAnimation()
     {
         if (isAnimationStarted)
         {
             return;
         }

         if (Width == 0)
         {


             startAnimationPreDrawListener = new ViewTreeObserverListner(ViewTreeObserver, this);
             ViewTreeObserver.AddOnPreDrawListener(startAnimationPreDrawListener);

             return;
         }

         Animator animator = getShimmerAnimation();
         animator.Start();
         isAnimationStarted = true;

     }


     private void releaseBitMaps()
     {
         canvasForShimmerMask = null;

         if (maskBitmap != null)
         {
             maskBitmap.Recycle();
             maskBitmap = null;
         }
     }


     private Bitmap getMaskBitmap()
     {
         if (maskBitmap == null)
         {
             maskBitmap = createBitmap(maskRect.Width(), Height);
         }

         return maskBitmap;
     }

     private void createShimmerPaint()
     {
         if (gradientTexturePaint != null)
         {
             return;
         }

         int edgeColor = reduceColorAlphaValueToZero(shimmerColor);
         float shimmerLineWidth = Width / 2 * maskWidth;
         float yPosition = (0 <= shimmerAngle) ? Height : 0;

         LinearGradient gradient = new LinearGradient(
                 0, yPosition,
                 (float)Math.Cos(degreesToRadians(shimmerAngle)) * shimmerLineWidth,
                 yPosition + (float)Math.Sin(degreesToRadians(shimmerAngle)) * shimmerLineWidth,
                 new int[] { edgeColor, shimmerColor, shimmerColor, edgeColor },
                 getGradientColorDistribution(),
                 Shader.TileMode.Clamp);

         BitmapShader maskBitmapShader = new BitmapShader(localMaskBitmap, Shader.TileMode.Clamp, Shader.TileMode.Clamp);

         ComposeShader composeShader = new ComposeShader(gradient, maskBitmapShader, PorterDuff.Mode.DstIn);

         gradientTexturePaint = new Paint();
         gradientTexturePaint.AntiAlias = (true);
         gradientTexturePaint.Dither = (true);
         gradientTexturePaint.FilterBitmap = (true);
         gradientTexturePaint.SetShader(composeShader);
     }

     public void stopShimmerAnimation()
     {
         if (startAnimationPreDrawListener != null)
         {
             ViewTreeObserver.RemoveOnPreDrawListener(startAnimationPreDrawListener);
         }

         resetShimmering();
     }

     private Animator getShimmerAnimation()
     {
         if (maskAnimator != null)
         {
             return maskAnimator;
         }
         if (maskRect == null)
         {
             maskRect = calculateBitmapMaskRect();
         }
         int animationToX = Width;
         int animationFromX;

         if (Width > maskRect.Width())
         {
             animationFromX = -animationToX;
         }
         else
         {
             animationFromX = -maskRect.Width();
         }

         int shimmerBitmapWidth = maskRect.Width();
         int shimmerAnimationFullLength = animationToX - animationFromX;

         maskAnimator = isAnimationReversed ? ValueAnimator.OfInt(shimmerAnimationFullLength, 0)
                 : ValueAnimator.OfInt(0, shimmerAnimationFullLength);
         maskAnimator.SetDuration(shimmerAnimationDuration);
         maskAnimator.RepeatCount = (ObjectAnimator.Infinite);
         maskAnimator.AddUpdateListener(new ShimmerAnimation(animationFromX));
         return maskAnimator;
     }

     private Bitmap createBitmap(int width, int height)
     {
         try
         {
             return Bitmap.CreateBitmap(width, height, Bitmap.Config.Alpha8);
         }
         catch (OutOfMemoryException e)
         {

             return null;
         }
     }

     private int getColor(int id)
     {
         if (Build.VERSION.SdkInt >= Build.VERSION_CODES.M)
         {
             return Context.GetColor(id);
         }
         else
         {
             //noinspection deprecation
             return Resources.GetColor(id);
         }
     }

     private int reduceColorAlphaValueToZero(int actualColor)
     {
         return Color.Argb(0, actualColor, actualColor, actualColor);
     }

     private Rect calculateBitmapMaskRect()
     {
         return new Rect(0, 0, calculateMaskWidth(), Height);
     }

     private int calculateMaskWidth()
     {
         double shimmerLineBottomWidth = (Width / 2 * maskWidth) / Math.Cos(degreesToRadians(Math.Abs(shimmerAngle)));
         double shimmerLineRemainingTopWidth = Height * Math.Tan(degreesToRadians(Math.Abs(shimmerAngle)));
         return (int)(shimmerLineBottomWidth + shimmerLineRemainingTopWidth);
     }

     public double degreesToRadians(double degrees)
     {
         return (degrees * Math.PI) / 180;
     }

     private float[] getGradientColorDistribution()
     {
         float[] colorDistribution = new float[4];

         colorDistribution[0] = 0;
         colorDistribution[3] = 1;

         colorDistribution[1] = 0.5F - gradientCenterColorWidth / 2F;
         colorDistribution[2] = 0.5F + gradientCenterColorWidth / 2F;

         return colorDistribution;
     }

     private void enableForcedSoftwareLayerIfNeeded()
     {
         if (Build.VERSION.SdkInt <= Build.VERSION_CODES.JellyBean)
         {
             SetLayerType(LayerType.Software, null);
         }
     }



     public void setShimmerColor(int shimmerColor)
     {
         this.shimmerColor = shimmerColor;
         resetIfStarted();
     }

     public void setShimmerAnimationDuration(int durationMillis)
     {
         this.shimmerAnimationDuration = durationMillis;
         resetIfStarted();
     }

     public void setAnimationReversed(bool animationReversed)
     {
         this.isAnimationReversed = animationReversed;
         resetIfStarted();
     }


     private void setShimmerAngle(int shimmerAngle)
     {
         if (shimmerAngle < MIN_ANGLE_VALUE || MAX_ANGLE_VALUE < shimmerAngle)
         {

         }
         this.shimmerAngle = shimmerAngle;
         resetIfStarted();
     }

     private void setGradientCenterColorWidth(float gradientCenterColorWidth)
     {
         if (gradientCenterColorWidth <= MIN_GRADIENT_CENTER_COLOR_WIDTH_VALUE
              || MAX_GRADIENT_CENTER_COLOR_WIDTH_VALUE <= gradientCenterColorWidth)
         {

         }

         this.gradientCenterColorWidth = gradientCenterColorWidth;
         resetIfStarted();
     }

     private void setMaskWidth(float maskWidth)
     {
         if (maskWidth <= MIN_MASK_WIDTH_VALUE || MAX_MASK_WIDTH_VALUE < maskWidth)
         {

         }

         this.maskWidth = maskWidth;
         resetIfStarted();
     }


}

1 个答案:

答案 0 :(得分:1)

检查您的.axml文件。您应该在axml文件中使用小写字母表示名称空间,并使用camelcase表示类名称(如https://stackoverflow.com/a/54932494/9335822中所示)。

更改您的xml文件,例如:

<jammbersplits.droid.customcontrols.ShimmerSplitsLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:id="@+id/shimmerLayout"
    ... />