Kotlin中带有Volley NetworkImageView的CircleImageView在布局中提供了android.view.InflateException

时间:2019-07-05 17:41:23

标签: android kotlin

创建了CircleImageView,扩展了NetworkImageView,并使用on布局从url动态显示圆形图像。但是在xml布局中,它提供了“ InflateException”二进制XML文件。

我使用的布局:

<com.xxxx.xxxxx.utility.CircleImageView
                    android:id="@+id/img"
                    android:layout_width="60dp"
                    android:layout_height="60dp"
                    android:layout_marginStart="2dp"
                    android:layout_marginTop="2dp"
                    android:layout_marginBottom="2dp"
                    android:scaleType="fitCenter"
                  android:background="@drawable/rounded_all_blue"/>

kotlin中的CircleImageView类文件:

1)CircleImageView:

class CircleImageView : NetworkImageView {

private val SCALE_TYPE = ScaleType.CENTER_CROP

private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888
private val COLORDRAWABLE_DIMENSION = 2

private val DEFAULT_BORDER_WIDTH = 0
private val DEFAULT_BORDER_COLOR = Color.BLACK
private val DEFAULT_BORDER_OVERLAY = false

private val mDrawableRect = RectF()
private val mBorderRect = RectF()

private val mShaderMatrix = Matrix()
private val mBitmapPaint = Paint()
private val mBorderPaint = Paint()

private var mBorderColor = DEFAULT_BORDER_COLOR
private var mBorderWidth = DEFAULT_BORDER_WIDTH

private var mBitmap: Bitmap? = null
private var mBitmapShader: BitmapShader? = null
private var mBitmapWidth: Int = 0
private var mBitmapHeight: Int = 0

private var mDrawableRadius: Float = 0.toFloat()
private var mBorderRadius: Float = 0.toFloat()

private var mColorFilter: ColorFilter? = null

private var mReady: Boolean = false
private var mSetupPending: Boolean = false
private var mBorderOverlay: Boolean = false

constructor(context:Context) : super(context) {
    init()
}

private fun init() {
    super.setScaleType(SCALE_TYPE)
    mReady = true

    if (mSetupPending) {
        setup()
        mSetupPending = false
    }
}

override fun getScaleType(): ImageView.ScaleType {
    return SCALE_TYPE
}

override fun setScaleType(scaleType: ImageView.ScaleType) {
    if (scaleType != SCALE_TYPE) {
        throw IllegalArgumentException(String.format("ScaleType %s not supported.", scaleType))
    }
}

override fun setAdjustViewBounds(adjustViewBounds: Boolean) {
    if (adjustViewBounds) {
        throw IllegalArgumentException("adjustViewBounds not supported.")
    }
}

    override fun onDraw(canvas: Canvas) {
    if (drawable == null) {
        return
    }

    canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), mDrawableRadius, mBitmapPaint)
    if (mBorderWidth !== 0) {
        canvas.drawCircle((width / 2).toFloat(), (height / 2).toFloat(), mBorderRadius, mBorderPaint)
    }
}

override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
    super.onSizeChanged(w, h, oldw, oldh)
    setup()
}

fun getBorderColor(): Int {
    return mBorderColor
}

fun setBorderColor(borderColor: Int) {
    if (borderColor == mBorderColor) {
        return
    }

    mBorderColor = borderColor
    mBorderPaint.color = mBorderColor
    invalidate()
}

fun setBorderColorResource(@ColorRes borderColorRes: Int) {
    setBorderColor(context.resources.getColor(borderColorRes))
}

fun getBorderWidth(): Int {
    return mBorderWidth
}

fun setBorderWidth(borderWidth: Int) {
    if (borderWidth == mBorderWidth) {
        return
    }

    mBorderWidth = borderWidth
    setup()
}

fun isBorderOverlay(): Boolean {
    return mBorderOverlay
}

fun setBorderOverlay(borderOverlay: Boolean) {
    if (borderOverlay == mBorderOverlay) {
        return
    }

    mBorderOverlay = borderOverlay
    setup()
}

override fun setImageBitmap(bm: Bitmap) {
    super.setImageBitmap(bm)
    mBitmap = bm
    setup()
}

override fun setImageDrawable(drawable: Drawable?) {
    super.setImageDrawable(drawable)
    mBitmap = getBitmapFromDrawable(drawable)
    setup()
}

override fun setImageResource(@DrawableRes resId: Int) {
    super.setImageResource(resId)
    mBitmap = getBitmapFromDrawable(drawable)
    setup()
}

override fun setImageURI(uri: Uri) {
    super.setImageURI(uri)
    mBitmap = getBitmapFromDrawable(drawable)
    setup()
}

override fun setColorFilter(cf: ColorFilter) {
    if (cf === mColorFilter) {
        return
    }

    mColorFilter = cf
    mBitmapPaint.colorFilter = mColorFilter
    invalidate()
}

private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? {
    if (drawable == null) {
        return null
    }

    if (drawable is BitmapDrawable) {
        return drawable.bitmap
    }

    try {
        val bitmap: Bitmap

        if (drawable is ColorDrawable) {
            bitmap = Bitmap.createBitmap(COLORDRAWABLE_DIMENSION, COLORDRAWABLE_DIMENSION, BITMAP_CONFIG)
        } else {
            bitmap = Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG)
        }

        val canvas = Canvas(bitmap)
        drawable.setBounds(0, 0, canvas.width, canvas.height)
        drawable.draw(canvas)
        return bitmap
    } catch (e: OutOfMemoryError) {
        return null
    }

}

private fun setup() {
    if (!mReady) {
        mSetupPending = true
        return
    }

    if (mBitmap == null) {
        return
    }

    mBitmapShader = BitmapShader(mBitmap, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)

    mBitmapPaint.isAntiAlias = true
    mBitmapPaint.shader = mBitmapShader

    mBorderPaint.style = Paint.Style.STROKE
    mBorderPaint.isAntiAlias = true
    mBorderPaint.color = mBorderColor
    mBorderPaint.setStrokeWidth(mBorderWidth.toFloat())

    mBitmapHeight = mBitmap!!.height
    mBitmapWidth = mBitmap!!.width

    mBorderRect.set(0F, 0F, width.toFloat(), height.toFloat())
    mBorderRadius = Math.min((mBorderRect.height() - mBorderWidth) / 2, (mBorderRect.width() - mBorderWidth) / 2)

    mDrawableRect.set(mBorderRect)
    if (!mBorderOverlay) {
        mDrawableRect.inset(mBorderWidth.toFloat(), mBorderWidth.toFloat())
    }
    mDrawableRadius = Math.min(mDrawableRect.height() / 2, mDrawableRect.width() / 2)

    updateShaderMatrix()
    invalidate()
}

private fun updateShaderMatrix() {
    val scale: Float
    var dx = 0f
    var dy = 0f

    mShaderMatrix.set(null)

    if (mBitmapWidth * mDrawableRect.height() > mDrawableRect.width() * mBitmapHeight) {
        scale = mDrawableRect.height() / mBitmapHeight as Float
        dx = (mDrawableRect.width() - mBitmapWidth * scale) * 0.5f
    } else {
        scale = mDrawableRect.width() / mBitmapWidth as Float
        dy = (mDrawableRect.height() - mBitmapHeight * scale) * 0.5f
    }

    mShaderMatrix.setScale(scale, scale)
    mShaderMatrix.postTranslate((dx + 0.5f).toInt() + mDrawableRect.left, (dy + 0.5f).toInt() + mDrawableRect.top)

    mBitmapShader?.setLocalMatrix(mShaderMatrix)
}

}

2)动态调用图像的方法

fun loadImage(url:String, avatar: CircleImageView){
    val imageLoader: ImageLoader by lazy {
        ImageLoader(ApiConnect.instance.requestQueue, LruBitmapCache())
    }
    avatar.setImageUrl(url,imageLoader);
 }

3)我们可以加载图像

APIController().loadImage(imageurlpath,holder.img)

当我使用“ NetworkImageView”时图像显示,但问题是它不适合圆形,我已经阅读并将“ CircleImageView”转换为kotlin并使用过,但是它给出了错误,请帮忙。

//错误日志:

2019-07-05 18:29:20.721 21385-21385/com.xxxx.xxxxxx E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.xxxx.xxxxxx, PID: 21385
android.view.InflateException: Binary XML file line #11: Binary XML file line #11: Error inflating class com.xxxx.xxxxxx.utility.CircleImageView
Caused by: android.view.InflateException: Binary XML file line #11: Error inflating class com.xxxx.xxxxx.utility.CircleImageView
Caused by: java.lang.NoSuchMethodException: <init> [class android.content.Context, interface android.util.AttributeSet]
    at java.lang.Class.getConstructor0(Class.java:2327)
    at java.lang.Class.getConstructor(Class.java:1725)

1 个答案:

答案 0 :(得分:0)

问题是您的自定义视图不能正确覆盖必要的构造函数。该错误为NoSuchMethodException,因为应该使用具有ContextAttributeSet的构造函数。这不存在。

您可以创建此构造函数并调用super(context, attributeSet)或使用JvmOverload批注。

因此,您可以像这样实现构造函数:

class CustomView : View {

    constructor(context: Context) : this(context, null)
    constructor(context: Context, attrs: AttributeSet?) : this(context, attrs, 0)

    constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr) {
        //do stuff
    }
}

或使用如下注释:

class CustomView @JvmOverloads constructor(
    context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : View(context, attrs, defStyleAttr) {

}