Guest User

Untitled

a guest
Mar 24th, 2018
82
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 9.17 KB | None | 0 0
  1. package com.jumpcorporation.jumpin.presentation.widget
  2.  
  3. import android.content.Context
  4. import android.graphics.*
  5. import android.graphics.drawable.BitmapDrawable
  6. import android.graphics.drawable.ColorDrawable
  7. import android.graphics.drawable.Drawable
  8. import android.net.Uri
  9. import android.support.annotation.ColorInt
  10. import android.support.annotation.DrawableRes
  11. import android.util.AttributeSet
  12. import android.widget.ImageView
  13. import com.jumpcorporation.jumpin.R
  14.  
  15. class HexagonImageView @JvmOverloads constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0)
  16. : ImageView(context, attrs, defStyleAttr) {
  17.  
  18. companion object {
  19. private val BITMAP_CONFIG = Bitmap.Config.ARGB_8888
  20. private const val COLOR_DRAWABLE_DIMENSION = 2
  21.  
  22. //default values
  23. private const val DEFAULT_BORDER_WIDTH = 0
  24. private const val DEFAULT_BORDER_PADDING = 0
  25. private const val DEFAULT_BORDER_COLOR = Color.BLACK
  26. private const val DEFAULT_BORDER_COLOR_SELECTED = Color.BLUE
  27. private const val DEFAULT_CORNER_RADIUS = 0f
  28. }
  29.  
  30. private var borderColor: Int
  31. private var borderWidth: Int
  32. private var cornerRadius: Float
  33. private var borderColorSelected: Int
  34. private var borderPadding: Int
  35.  
  36. private var bitmap: Bitmap? = null
  37. private var bitmapWidth: Int = 0
  38. private var bitmapHeight: Int = 0
  39. private lateinit var bitmapShader: BitmapShader
  40. private val shaderMatrix = Matrix()
  41. private val drawableRect = RectF()
  42. private val drawableBounds = RectF()
  43.  
  44. private val bitmapPaint: Paint
  45. private val borderPaint: Paint
  46. private lateinit var bitmapHexagonPath: Path
  47. private lateinit var borderHexagonPath: Path
  48.  
  49. private var selectStatus = false
  50.  
  51. init {
  52. val attributes = context.obtainStyledAttributes(attrs, R.styleable.HexagonImageView, defStyleAttr, 0)
  53.  
  54. borderWidth = attributes.getDimensionPixelSize(R.styleable.HexagonImageView_border_width, DEFAULT_BORDER_WIDTH)
  55. borderColor = attributes.getColor(R.styleable.HexagonImageView_border_color, DEFAULT_BORDER_COLOR)
  56. borderColorSelected = attributes.getColor(R.styleable.HexagonImageView_border_color_selected, DEFAULT_BORDER_COLOR_SELECTED)
  57. cornerRadius = attributes.getFloat(R.styleable.HexagonImageView_corner_radius, DEFAULT_CORNER_RADIUS)
  58. borderPadding = attributes.getDimensionPixelOffset(R.styleable.HexagonImageView_border_padding, DEFAULT_BORDER_PADDING)
  59.  
  60. attributes.recycle()
  61.  
  62. borderPaint = initBorderPaint()
  63. bitmapPaint = initBitmapPaint()
  64. }
  65.  
  66. override fun setAdjustViewBounds(adjustViewBounds: Boolean) {
  67. if (adjustViewBounds) {
  68. throw IllegalArgumentException("adjustViewBounds not supported.")
  69. }
  70. }
  71.  
  72. override fun onDraw(canvas: Canvas) {
  73. if (bitmap == null) return
  74. canvas.drawPath(bitmapHexagonPath, bitmapPaint)
  75. if(borderWidth != 0) canvas.drawPath(borderHexagonPath, borderPaint)
  76. canvas.save()
  77. }
  78.  
  79. override fun onSizeChanged(w: Int, h: Int, oldw: Int, oldh: Int) {
  80. super.onSizeChanged(w, h, oldw, oldh)
  81. setup()
  82. }
  83.  
  84. override fun setPadding(left: Int, top: Int, right: Int, bottom: Int) {
  85. super.setPadding(left, top, right, bottom)
  86. setup()
  87. }
  88.  
  89. override fun setPaddingRelative(start: Int, top: Int, end: Int, bottom: Int) {
  90. super.setPaddingRelative(start, top, end, bottom)
  91. setup()
  92. }
  93.  
  94. override fun setImageBitmap(bm: Bitmap?) {
  95. super.setImageBitmap(bm)
  96. initializeBitmap()
  97. }
  98.  
  99. override fun setImageDrawable(drawable: Drawable?) {
  100. super.setImageDrawable(drawable)
  101. initializeBitmap()
  102. }
  103.  
  104. override fun setImageResource(@DrawableRes resId: Int) {
  105. super.setImageResource(resId)
  106. initializeBitmap()
  107. }
  108.  
  109. override fun setImageURI(uri: Uri?) {
  110. super.setImageURI(uri)
  111. initializeBitmap()
  112. }
  113.  
  114. fun getBorderColor(): Int {
  115. return borderColor
  116. }
  117.  
  118. fun setBorderColor(@ColorInt borderColor: Int) {
  119. if (borderColor == this.borderColor) return
  120.  
  121. this.borderColor = borderColor
  122. borderPaint.color = this.borderColor
  123. invalidate()
  124. }
  125.  
  126. fun getBorderWidth(): Int {
  127. return borderWidth
  128. }
  129.  
  130. fun setBorderWidth(borderWidth: Int) {
  131. if (borderWidth == this.borderWidth) return
  132.  
  133. this.borderWidth = borderWidth
  134. setup()
  135. }
  136.  
  137. fun onCustomClick() {
  138. if (selectStatus) {
  139. borderPaint.color = borderColor
  140. selectStatus = false
  141. } else {
  142. borderPaint.color = borderColorSelected
  143. selectStatus = true
  144. }
  145. invalidate()
  146. }
  147.  
  148. private fun initializeBitmap() {
  149. bitmap = getBitmapFromDrawable(drawable)
  150. setup()
  151. }
  152.  
  153. private fun initBorderPaint(): Paint {
  154. val paint = Paint(Paint.ANTI_ALIAS_FLAG)
  155. paint.style = Paint.Style.STROKE
  156. paint.strokeWidth = borderWidth.toFloat()
  157. paint.color = borderColor
  158. return paint
  159. }
  160.  
  161. private fun initBitmapPaint() = Paint(Paint.ANTI_ALIAS_FLAG)
  162.  
  163. private fun setup() {
  164. if (width == 0 && height == 0) return
  165.  
  166. if (bitmap == null) {
  167. invalidate()
  168. return
  169. }
  170.  
  171. bitmapHexagonPath = calculateBitmapHexagonPath()
  172. borderHexagonPath = calculateBorderHexagonPath()
  173.  
  174. bitmapShader = BitmapShader(bitmap!!, Shader.TileMode.CLAMP, Shader.TileMode.CLAMP)
  175.  
  176. bitmapPaint.shader = bitmapShader
  177.  
  178. bitmapHeight = bitmap!!.height
  179. bitmapWidth = bitmap!!.width
  180.  
  181. drawableBounds.set(calculateDrawableBounds())
  182.  
  183. drawableRect.set(drawableBounds)
  184. drawableRect.inset(borderWidth.toFloat(), borderWidth.toFloat())
  185.  
  186. updateShaderMatrix()
  187. invalidate()
  188. }
  189.  
  190. private fun getBitmapFromDrawable(drawable: Drawable?): Bitmap? {
  191. if (drawable == null) {
  192. return null
  193. }
  194.  
  195. if (drawable is BitmapDrawable) {
  196. return drawable.bitmap
  197. }
  198.  
  199. return try {
  200. val bitmap: Bitmap = if (drawable is ColorDrawable) {
  201. Bitmap.createBitmap(COLOR_DRAWABLE_DIMENSION, COLOR_DRAWABLE_DIMENSION, BITMAP_CONFIG)
  202. } else {
  203. Bitmap.createBitmap(drawable.intrinsicWidth, drawable.intrinsicHeight, BITMAP_CONFIG)
  204. }
  205.  
  206. val canvas = Canvas(bitmap)
  207. drawable.setBounds(0, 0, canvas.width, canvas.height)
  208. drawable.draw(canvas)
  209. bitmap
  210. } catch (e: Exception) {
  211. e.printStackTrace()
  212. null
  213. }
  214. }
  215.  
  216. private fun calculateDrawableBounds(): RectF {
  217. val availableWidth = width - paddingLeft - paddingRight
  218. val availableHeight = height - paddingTop - paddingBottom
  219.  
  220. val sideLength = Math.min(availableWidth, availableHeight)
  221.  
  222. val left = paddingLeft + (availableWidth - sideLength) / 2f
  223. val top = paddingTop + (availableHeight - sideLength) / 2f
  224.  
  225. return RectF(left, top, left + sideLength, top + sideLength)
  226. }
  227.  
  228. private fun updateShaderMatrix() {
  229. val scale: Float
  230. var dx = 0f
  231. var dy = 0f
  232.  
  233. shaderMatrix.set(null)
  234.  
  235. if (bitmapWidth * drawableRect.height() > drawableRect.width() * bitmapHeight) {
  236. scale = (drawableRect.height() / bitmapHeight.toFloat())
  237. dx = (drawableRect.width() - bitmapWidth * scale) * 0.5f
  238. } else {
  239. scale = (drawableRect.width() / bitmapWidth.toFloat())
  240. dy = (drawableRect.height() - bitmapHeight * scale) * 0.5f
  241. }
  242.  
  243. shaderMatrix.setScale(scale, scale)
  244. shaderMatrix.postTranslate((dx + 0.5f).toInt() + drawableRect.left, (dy + 0.5f).toInt() + drawableRect.top)
  245.  
  246. bitmapShader.setLocalMatrix(shaderMatrix)
  247. }
  248.  
  249. private fun calculateBitmapHexagonPath(): Path {
  250. var bitmapHexagonRadius = calculateInitialHexagonRadius()
  251. bitmapHexagonRadius -= (borderWidth + borderPadding - 1)// additional -1 uses to hide difference between border inner curve and image outer curve
  252. bitmapPaint.pathEffect = CornerPathEffect(bitmapHexagonRadius * cornerRadius)
  253.  
  254. return calculateHexagonPath(bitmapHexagonRadius)
  255. }
  256.  
  257. private fun calculateBorderHexagonPath(): Path {
  258. var borderHexagonRadius = calculateInitialHexagonRadius()
  259. borderHexagonRadius -= borderWidth / 2
  260. borderPaint.pathEffect = CornerPathEffect(borderHexagonRadius * cornerRadius)
  261.  
  262. return calculateHexagonPath(borderHexagonRadius)
  263. }
  264.  
  265. private fun calculateHexagonPath(radius: Int): Path {
  266. val path = Path()
  267. val triangleHeight = Math.sqrt(3.0).toFloat() * radius / 2
  268. val centerX = width.toFloat() / 2
  269. val centerY = height.toFloat() / 2
  270. path.moveTo(centerX, centerY + radius)
  271. path.lineTo(centerX - triangleHeight, centerY + radius / 2)
  272. path.lineTo(centerX - triangleHeight, centerY - radius / 2)
  273. path.lineTo(centerX, centerY - radius)
  274. path.lineTo(centerX + triangleHeight, centerY - radius / 2)
  275. path.lineTo(centerX + triangleHeight, centerY + radius / 2)
  276. path.close()
  277. return path
  278. }
  279.  
  280. private fun calculateInitialHexagonRadius() = if (width > height) height / 2 else width / 2
  281. }
Add Comment
Please, Sign In to add comment