Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- package com.jumpcorporation.jumpin.presentation.widget
- import android.content.Context
- import android.graphics.*
- import android.graphics.drawable.BitmapDrawable
- import android.graphics.drawable.ColorDrawable
- import android.graphics.drawable.Drawable
- import android.net.Uri
- import android.support.annotation.ColorInt
- import android.support.annotation.DrawableRes
- import android.util.AttributeSet
- import android.widget.ImageView
- import com.jumpcorporation.jumpin.R
- class HexagonImageView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
- : ImageView(context, attrs, defStyleAttr) {
- companion object {
- private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888
- private const val COLOR_DRAWABLE_DIMENSION = 2
- //default values
- private const val DEFAULT_BORDER_WIDTH = 0
- private const val DEFAULT_BORDER_PADDING = 0
- private const val DEFAULT_BORDER_COLOR = Color.BLACK
- private const val DEFAULT_BORDER_COLOR_SELECTED = Color.BLUE
- private const val DEFAULT_CORNER_RADIUS = 0f
- }
- private var borderColor: Int
- private var borderWidth: Int
- private var cornerRadius: Float
- private var borderColorSelected: Int
- private var borderPadding: Int
- private var bitmap: Bitmap? = null
- private var bitmapWidth: Int = 0
- private var bitmapHeight: Int = 0
- private lateinit var bitmapShader: BitmapShader
- private val shaderMatrix = Matrix()
- private val drawableRect = RectF()
- private val drawableBounds = RectF()
- private val bitmapPaint: Paint
- private val borderPaint: Paint
- private lateinit var bitmapHexagonPath: Path
- private lateinit var borderHexagonPath: Path
- private var selectStatus = false
- init {
- val attributes = context.obtainStyledAttributes(attrs, R.styleable.HexagonImageView, defStyleAttr, 0)
- borderWidth = attributes.getDimensionPixelSize(R.styleable.HexagonImageView_border_width, DEFAULT_BORDER_WIDTH)
- borderColor = attributes.getColor(R.styleable.HexagonImageView_border_color, DEFAULT_BORDER_COLOR)
- borderColorSelected = attributes.getColor(R.styleable.HexagonImageView_border_color_selected, DEFAULT_BORDER_COLOR_SELECTED)
- cornerRadius = attributes.getFloat(R.styleable.HexagonImageView_corner_radius, DEFAULT_CORNER_RADIUS)
- borderPadding = attributes.getDimensionPixelOffset(R.styleable.HexagonImageView_border_padding, DEFAULT_BORDER_PADDING)
- attributes.recycle()
- borderPaint = initBorderPaint()
- bitmapPaint = initBitmapPaint()
- }
- override fun setAdjustViewBounds(adjustViewBounds: Boolean) {
- if (adjustViewBounds) {
- throw IllegalArgumentException("adjustViewBounds not supported.")
- }
- }
- override fun onDraw(canvas: Canvas) {
- if (bitmap == null) return
- canvas.drawPath(bitmapHexagonPath, bitmapPaint)
- if(borderWidth != 0) canvas.drawPath(borderHexagonPath, borderPaint)
- canvas.save()
- }
- override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
- super.onSizeChanged(w, h, oldw, oldh)
- setup()
- }
- override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
- super.setPadding(left, top, right, bottom)
- setup()
- }
- override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
- super.setPaddingRelative(start, top, end, bottom)
- setup()
- }
- override fun setImageBitmap(bm: Bitmap?) {
- super.setImageBitmap(bm)
- initializeBitmap()
- }
- override fun setImageDrawable(drawable: Drawable?) {
- super.setImageDrawable(drawable)
- initializeBitmap()
- }
- override fun setImageResource(@DrawableRes resId: Int) {
- super.setImageResource(resId)
- initializeBitmap()
- }
- override fun setImageURI(uri: Uri?) {
- super.setImageURI(uri)
- initializeBitmap()
- }
- fun getBorderColor(): Int {
- return borderColor
- }
- fun setBorderColor(@ColorInt borderColor: Int) {
- if (borderColor == this.borderColor) return
- this.borderColor = borderColor
- borderPaint.color = this.borderColor
- invalidate()
- }
- fun getBorderWidth(): Int {
- return borderWidth
- }
- fun setBorderWidth(borderWidth: Int) {
- if (borderWidth == this.borderWidth) return
- this.borderWidth = borderWidth
- setup()
- }
- fun onCustomClick() {
- if (selectStatus) {
- borderPaint.color = borderColor
- selectStatus = false
- } else {
- borderPaint.color = borderColorSelected
- selectStatus = true
- }
- invalidate()
- }
- private fun initializeBitmap() {
- bitmap = getBitmapFromDrawable(drawable)
- setup()
- }
- private fun initBorderPaint(): Paint {
- val paint = Paint(Paint.ANTI_ALIAS_FLAG)
- paint.style = Paint.Style.STROKE
- paint.strokeWidth = borderWidth.toFloat()
- paint.color = borderColor
- return paint
- }
- private fun initBitmapPaint() = Paint(Paint.ANTI_ALIAS_FLAG)
- private fun setup() {
- if (width == 0 && height == 0) return
- if (bitmap == null) {
- invalidate()
- return
- }
- bitmapHexagonPath = calculateBitmapHexagonPath()
- borderHexagonPath = calculateBorderHexagonPath()
- bitmapShader = BitmapShader(bitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
- bitmapPaint.shader = bitmapShader
- bitmapHeight = bitmap!!.height
- bitmapWidth = bitmap!!.width
- drawableBounds.set(calculateDrawableBounds())
- drawableRect.set(drawableBounds)
- drawableRect.inset(borderWidth.toFloat(), borderWidth.toFloat())
- updateShaderMatrix()
- invalidate()
- }
- private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? {
- if (drawable == null) {
- return null
- }
- if (drawable is BitmapDrawable) {
- return drawable.bitmap
- }
- return try {
- val bitmap: Bitmap = if (drawable is ColorDrawable) {
- Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG)
- } else {
- Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG)
- }
- val canvas = Canvas(bitmap)
- drawable.setBounds(0, 0, canvas.width, canvas.height)
- drawable.draw(canvas)
- bitmap
- } catch (e: Exception) {
- e.printStackTrace()
- null
- }
- }
- private fun calculateDrawableBounds(): RectF {
- val availableWidth = width - paddingLeft - paddingRight
- val availableHeight = height - paddingTop - paddingBottom
- val sideLength = Math.min(availableWidth, availableHeight)
- val left = paddingLeft + (availableWidth - sideLength) / 2f
- val top = paddingTop + (availableHeight - sideLength) / 2f
- return RectF(left, top, left + sideLength, top + sideLength)
- }
- private fun updateShaderMatrix() {
- val scale: Float
- var dx = 0f
- var dy = 0f
- shaderMatrix.set(null)
- if (bitmapWidth * drawableRect.height() > drawableRect.width() * bitmapHeight) {
- scale = (drawableRect.height() / bitmapHeight.toFloat())
- dx = (drawableRect.width() - bitmapWidth * scale) * 0.5f
- } else {
- scale = (drawableRect.width() / bitmapWidth.toFloat())
- dy = (drawableRect.height() - bitmapHeight * scale) * 0.5f
- }
- shaderMatrix.setScale(scale, scale)
- shaderMatrix.postTranslate((dx + 0.5f).toInt() + drawableRect.left, (dy + 0.5f).toInt() + drawableRect.top)
- bitmapShader.setLocalMatrix(shaderMatrix)
- }
- private fun calculateBitmapHexagonPath(): Path {
- var bitmapHexagonRadius = calculateInitialHexagonRadius()
- bitmapHexagonRadius -= (borderWidth + borderPadding - 1)// additional -1 uses to hide difference between border inner curve and image outer curve
- bitmapPaint.pathEffect = CornerPathEffect(bitmapHexagonRadius * cornerRadius)
- return calculateHexagonPath(bitmapHexagonRadius)
- }
- private fun calculateBorderHexagonPath(): Path {
- var borderHexagonRadius = calculateInitialHexagonRadius()
- borderHexagonRadius -= borderWidth / 2
- borderPaint.pathEffect = CornerPathEffect(borderHexagonRadius * cornerRadius)
- return calculateHexagonPath(borderHexagonRadius)
- }
- private fun calculateHexagonPath(radius: Int): Path {
- val path = Path()
- val triangleHeight = Math.sqrt(3.0).toFloat() * radius / 2
- val centerX = width.toFloat() / 2
- val centerY = height.toFloat() / 2
- path.moveTo(centerX, centerY + radius)
- path.lineTo(centerX - triangleHeight, centerY + radius / 2)
- path.lineTo(centerX - triangleHeight, centerY - radius / 2)
- path.lineTo(centerX, centerY - radius)
- path.lineTo(centerX + triangleHeight, centerY - radius / 2)
- path.lineTo(centerX + triangleHeight, centerY + radius / 2)
- path.close()
- return path
- }
- private fun calculateInitialHexagonRadius() = if (width > height) height / 2 else width / 2
- }
Add Comment
Please, Sign In to add comment