【創新實訓 第八週】 Android端正式動土 2019.5.13

本週工作進展

安卓移動端“西瓜街景”完成基本框架,完成了最主要的功能:街景的繪製顯示。等待服務器端完成後編寫網絡模塊。


詳細工作內容

1. 正方形 Layout

import android.content.Context
import android.util.AttributeSet
import android.widget.RelativeLayout

class SquareRelativeLayout : RelativeLayout {
    constructor(context: Context?) : super(context)
    constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)

    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        setMeasuredDimension(getDefaultSize(0, widthMeasureSpec), getDefaultSize(0, heightMeasureSpec))

        // Children are just made to fill our space.
        val childWidthSize = measuredWidth
        val childHeightSize = measuredHeight
        //高度和寬度一樣
        val widthMeasureSpec = MeasureSpec.makeMeasureSpec(childWidthSize, MeasureSpec.EXACTLY)
        val heightMeasureSpec = widthMeasureSpec
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)

    }
}

 

2. 打開相機或相冊

private fun onMenuItemClick(menuItem: MenuItem): Boolean {
    when (menuItem.itemId) {
        R.id.menu_item_select          -> {
            // 選擇照片
            val intent = Intent(Intent.ACTION_PICK)
            intent.type = "image/*"
            startActivityForResult(intent, REQUEST_ALBUM)
        }
        R.id.menu_item_take_photograph -> {
            // 打開相機
            val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
            intent.putExtra(MediaStore.EXTRA_OUTPUT, tempPhotoUri)
            startActivityForResult(intent, REQUEST_CAMERA)
        }
    }
    return false
}

3. 街景預覽

街景預覽包含基本操作如手勢放大縮小移動等,還要進行原圖和街景文本識別貼圖之間的切換。效果如下:

文本及其位置爲隨機生成。

    

圖像手勢操作交由 SubsamplingScaleImageView 控件完成,兩個 ssiv 分別加載原圖和帶有街景文字識別結果的圖片,通過單擊操作切換顯示。

fun draw(
    streetScape: TranslateStreetScape,
    textColor: Int = Color.WHITE,
    crowdingTextColor: Int = Color.CYAN,
    showDarkMask: Boolean = true,
    darkMaskColor: Int = Color.parseColor("#66000000"),
    showTextBorder: Boolean = false,
    textBorderColor: Int = Color.parseColor("#66000000")
): Bitmap {
    val bitmap = BitmapFactory
        .decodeFile(streetScape.photoPath)
        .copy(Bitmap.Config.ARGB_8888, true)

    val canvas = Canvas(bitmap)
    val paint = Paint()

    // 背景遮罩
    if (showDarkMask) {
        paint.color = darkMaskColor
        paint.style = Paint.Style.FILL_AND_STROKE
        canvas.drawRect(
            0f, 0f, bitmap.width.toFloat(), bitmap.height.toFloat(), paint)
    }

    // 繪製傾斜文本框
    if (showTextBorder) {
        paint.color = textBorderColor
        streetScape.textBoxList.forEach {
            val cx = (it.x0 + it.x1) / 2
            val cy = (it.y0 + it.y1) / 2
            canvas.rotate(it.degree, cx, cy)
            canvas.drawRect(it.x0, it.y0, it.x1, it.y1, paint)
            canvas.rotate(-it.degree, cx, cy)
        }
    }

    // 繪製文本
    streetScape.textBoxList.forEach { box ->
        val maxTextSize = min(bitmap.width, bitmap.height) / 10f
        val minTextSize = min(bitmap.width, bitmap.height) / 30f
        val textSizeStep = min(bitmap.width, bitmap.height) / 100f
        // 先把字符串按行分割,每行最少1個字符
        // 每行平分文本框的高
        val lines = mutableListOf<String>()
        paint.color = crowdingTextColor
        paint.textSize = maxTextSize + textSizeStep
        while (paint.textSize > minTextSize) {
            paint.textSize -= textSizeStep
            var text = box.text
            lines.clear()
            val textHeight = abs(paint.fontMetrics.let { it.top + it.bottom })
            // 切行
            while (!text.isBlank()) {
                val index = paint
                    .breakText(text, true, box.x1 - box.x0, null)
                    .let { max(it, 1) }
                lines.add(text.substring(0, index))
                text = text.substring(index)
            }
            if (textHeight < (box.y1 - box.y0) / (lines.size.let { if (it > 1) it + 1 else 1 })) {
                paint.color = textColor
                break
            }
        }
        // 旋轉畫布
        val cx = (box.x0 + box.x1) / 2
        val cy = (box.y0 + box.y1) / 2
        canvas.rotate(box.degree, cx, cy)

        // 繪製文字
        val count = lines.size
        for (i in lines.indices) {
            val line = lines[i]
            val my = box.y0 + (box.y1 - box.y0) * (i + 1) / (count + 1)
            canvas.drawText(line, box.x0, my + abs(paint.fontMetrics.top / 3), paint)
        }

        // 畫布轉回來
        canvas.rotate(-box.degree, cx, cy)
    }
    return bitmap
}

下一步計劃

  • 等待檢測識別模塊完成後加入網絡模塊;
  • 考慮加入定位系統,讓APP主題更加貼近“街景”。

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章