本週工作進展
安卓移動端“西瓜街景”完成基本框架,完成了最主要的功能:街景的繪製顯示。等待服務器端完成後編寫網絡模塊。
詳細工作內容
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主題更加貼近“街景”。