iT邦幫忙

2018 iT 邦幫忙鐵人賽
DAY 24
0

Painter
提供一個畫板,讓使用者可以通過手指在上面畫畫。
可以將畫好的內容存到相簿當中。

Components

  • View
  • Canvas
  • File
  • Bitmap

在 Canvas 上畫圖

Paint 對象

Paint 對象用來定義畫筆的風格,比如顏色、粗細等等,比如

  • Paint.style - 繪製模式
  • paint.setColor(int Color) - 顏色
  • Paint.strokeWidth - 線條寬度
  • Paint.isAntiAlias - 抗鋸齒開關
    private fun setupPaint() {
        paint = Paint()
        paint.setColor(Color.GREEN)
        paint.strokeWidth = 5f
        paint.style = Paint.Style.STROKE
        paint.strokeCap = Paint.Cap.ROUND
        paint.isAntiAlias = true
    }

可以到官方文件上查更多有關 CanvasPaint 的資料


PaintBoard

我們建立一個 View 來讓使用者可以在上面畫畫。

Canvas 雖然是一個畫布,但實際上繪畫過程中所產生的內容都是存在 Canvas 的 bitmap 屬性中。

所以我們這裡初始化了一個 bitmap 放到 Canvas 中,在之後也會使用這個 bitmap 來將畫好的圖片存到相簿中。

(如果對 ARGB_8888 有疑慮可以參考之前的文章

    private var paint: Paint
    private var bitmap: Bitmap
    private var mCanvas: Canvas

    private var startX:Float = 0f
    private var startY:Float = 0f

    init {
        // bitmap
        val width = Resources.getSystem().displayMetrics.widthPixels
        bitmap = Bitmap.createBitmap(width, 800, Bitmap.Config.ARGB_8888)

        // Canvas
        mCanvas = Canvas(bitmap)
        mCanvas.drawColor(Color.GRAY)

        // Paint
        paint = Paint()
        paint.setColor(Color.BLACK)
        paint.setStrokeWidth(10f)
    }

saveBitmap

    fun saveBitmap(stream: OutputStream) {
        bitmap.compress(Bitmap.CompressFormat.JPEG, 100, stream)

    }

在 layout/activity_main.xml 中,引入 PaintBoard

    <devdon.com.painter.PaintBoard
        android:id="@+id/layout_paint_board"
        android:layout_width="match_parent"
        android:layout_height="300dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

BoardActivity

在 AndroidManifest.xml 中,加入存圖片的權限請求

<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

判斷使用者是否同意保存圖片,如果尚未允許則跳出請求

    private fun checkWritable():Boolean {
        if(ActivityCompat.checkSelfPermission(this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED){
            ActivityCompat.requestPermissions(this, arrayOf(Manifest.permission.WRITE_EXTERNAL_STORAGE),0)
            return false
        } else {
            return true
        }
    }

當使用者點下 SAVE 的時候,將圖片存到主要儲存卡上

而圖片的檔名根據當下的時間產生一個檔名(如果是同一個檔名會覆蓋)。

    private val saveClickHandler = View.OnClickListener { view ->
        if(checkWritable()){
            try {
                val fileName = (System.currentTimeMillis() / 1000).toString() + ".jpg"
                val file = File(Environment.getExternalStorageDirectory(), fileName)
                val stream = FileOutputStream(file)
                paintBoard.saveBitmap(stream)
                stream.close()

                val intent = Intent()
                intent.setAction(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE)
                intent.setData(Uri.fromFile(Environment.getExternalStorageDirectory()))
                sendBroadcast(intent)

                Toast.makeText(this, "Save Success", Toast.LENGTH_SHORT).show()

            } catch(e:Exception) {
                println(e)
                Toast.makeText(this, "Save Failed", Toast.LENGTH_SHORT).show()

            }
        }

    }

在相簿裡面就會看到我們剛才畫好的內容

https://ithelp.ithome.com.tw/upload/images/20171227/20107329oi3QmTG6OX.png


筆記

  • 研究:如何通過 Code 把 BaseBoard 放到 Activity 中,而不是通過 Layout(類似於 iOS 的 AddSubView)
  • TODO:畫板重置的實踐

參考


上一篇
Kotlin 開發第 23天 GoogleVoice (RecognizerIntent)
下一篇
Kotlin 開發第 25 天 FaceRecognizer (FaceDetector)
系列文
Kotlin 30 天,通過每天一個小 demo 學習 Android 開發30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言