为微光布局创建自定义视图时出错。 参考: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();
}
}
答案 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"
... />