实时视频UI

This commit is contained in:
2026-05-06 10:34:07 +08:00
parent 4e714ee7b6
commit a3115b6b86
25 changed files with 1212 additions and 1 deletions

View File

@@ -74,4 +74,6 @@ dependencies {
implementation("com.github.bumptech.glide:glide:4.15.1")
//Glide 依赖
implementation("com.github.bumptech.glide:glide:4.16.0")
// ZXing 二维码扫描库
implementation("com.google.zxing:core:3.5.2")
}

View File

@@ -23,6 +23,12 @@
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.DefenseApplication">
<activity
android:name=".liveVideo.LiveVideoActivity"
android:exported="false" />
<activity
android:name=".home.ScanActivity"
android:exported="false" />
<activity
android:name=".home.SetNameActivity"
android:exported="false" />

View File

@@ -75,7 +75,7 @@ class HomeMenuFragment : Fragment() {
startActivity(intent)
}
binding.addFamily.setOnClickListener {
val intent = Intent(requireContext(), AddFamilyActivity::class.java)
val intent = Intent(requireContext(), ScanActivity::class.java)
startActivity(intent)
}
}

View File

@@ -0,0 +1,291 @@
package com.example.defenseapplication.home
import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.ImageFormat
import android.graphics.Matrix
import android.graphics.RectF
import android.graphics.SurfaceTexture
import android.hardware.Camera
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.provider.MediaStore
import android.view.SurfaceHolder
import android.view.SurfaceView
import android.view.View
import android.view.animation.Animation
import android.view.animation.LinearInterpolator
import android.view.animation.TranslateAnimation
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.example.defenseapplication.R
import com.example.defenseapplication.databinding.ScanActivityBinding
import com.google.zxing.*
import com.google.zxing.common.HybridBinarizer
import java.util.*
class ScanActivity : AppCompatActivity(), SurfaceHolder.Callback {
private lateinit var binding: ScanActivityBinding
private var camera: Camera? = null
private var isFlashlightOn = false
private var scanHandler: Handler? = null
private var scanRunnable: Runnable? = null
private val REQUEST_CODE_CAMERA = 100
private val REQUEST_CODE_ALBUM = 101
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ScanActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
initView()
initListener()
startScanLineAnimation()
}
private fun initView() {
binding.surfaceView.holder.addCallback(this)
}
private fun initListener() {
binding.btnBack.setOnClickListener {
finish()
}
binding.llAlbum.setOnClickListener {
openAlbum()
}
binding.llFlashlight.setOnClickListener {
toggleFlashlight()
}
}
private fun startScanLineAnimation() {
val animation = TranslateAnimation(
Animation.RELATIVE_TO_PARENT, 0f,
Animation.RELATIVE_TO_PARENT, 0f,
Animation.RELATIVE_TO_PARENT, 0f,
Animation.RELATIVE_TO_PARENT, 1f
)
animation.duration = 2000
animation.repeatCount = Animation.INFINITE
animation.interpolator = LinearInterpolator()
binding.scanLine.startAnimation(animation)
}
private fun openAlbum() {
val intent = Intent(Intent.ACTION_PICK, MediaStore.Images.Media.EXTERNAL_CONTENT_URI)
startActivityForResult(intent, REQUEST_CODE_ALBUM)
}
private fun toggleFlashlight() {
if (camera == null) {
Toast.makeText(this, "相机未准备好", Toast.LENGTH_SHORT).show()
return
}
isFlashlightOn = !isFlashlightOn
val params = camera?.parameters
if (isFlashlightOn) {
params?.flashMode = Camera.Parameters.FLASH_MODE_TORCH
binding.ivFlashlight.setColorFilter(ContextCompat.getColor(this, R.color.green))
} else {
params?.flashMode = Camera.Parameters.FLASH_MODE_OFF
binding.ivFlashlight.clearColorFilter()
}
camera?.parameters = params
}
private fun checkCameraPermission(): Boolean {
return ContextCompat.checkSelfPermission(
this,
Manifest.permission.CAMERA
) == PackageManager.PERMISSION_GRANTED
}
private fun requestCameraPermission() {
ActivityCompat.requestPermissions(
this,
arrayOf(Manifest.permission.CAMERA),
REQUEST_CODE_CAMERA
)
}
private fun openCamera() {
if (!checkCameraPermission()) {
requestCameraPermission()
return
}
try {
camera = Camera.open()
camera?.setDisplayOrientation(90)
val params = camera?.parameters
params?.previewFormat = ImageFormat.NV21
val sizes = params?.supportedPreviewSizes
val optimalSize = getOptimalPreviewSize(sizes, binding.surfaceView.width, binding.surfaceView.height)
if (optimalSize != null) {
params?.setPreviewSize(optimalSize.width, optimalSize.height)
}
camera?.parameters = params
camera?.setPreviewDisplay(binding.surfaceView.holder)
camera?.startPreview()
startScanDecode()
} catch (e: Exception) {
Toast.makeText(this, "无法打开相机", Toast.LENGTH_SHORT).show()
}
}
private fun getOptimalPreviewSize(sizes: List<Camera.Size>?, w: Int, h: Int): Camera.Size? {
if (sizes == null) return null
var optimalSize: Camera.Size? = null
val targetRatio = h.toDouble() / w.toDouble()
for (size in sizes) {
val ratio = size.width.toDouble() / size.height.toDouble()
if (Math.abs(ratio - targetRatio) < 0.01) {
optimalSize = size
break
}
}
if (optimalSize == null) {
var minDiff = Int.MAX_VALUE
for (size in sizes) {
val diff = Math.abs(size.width - w) + Math.abs(size.height - h)
if (diff < minDiff) {
optimalSize = size
minDiff = diff
}
}
}
return optimalSize
}
private fun startScanDecode() {
scanHandler = Handler(Looper.getMainLooper())
scanRunnable = object : Runnable {
override fun run() {
decodeQRCode()
scanHandler?.postDelayed(this, 100)
}
}
scanHandler?.post(scanRunnable!!)
}
private fun decodeQRCode() {
if (camera == null) return
try {
val parameters = camera?.parameters
val size = parameters?.previewSize
if (size == null) return
val data = ByteArray(size.width * size.height * 3 / 2)
camera?.setOneShotPreviewCallback { bytes, _ ->
val source = PlanarYUVLuminanceSource(
bytes, size.width, size.height, 0, 0,
size.width, size.height, false
)
val binarizer = HybridBinarizer(source)
val bitmap = BinaryBitmap(binarizer)
val reader = MultiFormatReader()
val hints = Hashtable<DecodeHintType, Any>()
hints[DecodeHintType.CHARACTER_SET] = "UTF-8"
reader.setHints(hints)
try {
val result = reader.decode(bitmap)
handleScanResult(result.text)
} catch (e: Exception) {
}
}
} catch (e: Exception) {
}
}
private fun handleScanResult(result: String) {
stopScanDecode()
camera?.stopPreview()
Toast.makeText(this, "扫描结果: $result", Toast.LENGTH_SHORT).show()
val intent = Intent(this, AddFamilyActivity::class.java)
intent.putExtra("device_code", result)
startActivity(intent)
finish()
}
private fun stopScanDecode() {
scanRunnable?.let { scanHandler?.removeCallbacks(it) }
scanHandler = null
scanRunnable = null
}
override fun surfaceCreated(holder: SurfaceHolder) {
openCamera()
}
override fun surfaceChanged(holder: SurfaceHolder, format: Int, width: Int, height: Int) {
if (camera != null) {
camera?.stopPreview()
try {
camera?.setPreviewDisplay(holder)
camera?.startPreview()
} catch (e: Exception) {
}
}
}
override fun surfaceDestroyed(holder: SurfaceHolder) {
stopScanDecode()
camera?.stopPreview()
camera?.release()
camera = null
}
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<String>, grantResults: IntArray) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_CAMERA) {
if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
openCamera()
} else {
Toast.makeText(this, "需要相机权限", Toast.LENGTH_SHORT).show()
finish()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode == REQUEST_CODE_ALBUM && resultCode == RESULT_OK && data != null) {
val uri = data.data
uri?.let {
Toast.makeText(this, "已选择图片", Toast.LENGTH_SHORT).show()
}
}
}
override fun onDestroy() {
super.onDestroy()
stopScanDecode()
camera?.stopPreview()
camera?.release()
camera = null
}
}

View File

@@ -0,0 +1,133 @@
package com.example.defenseapplication.liveVideo
import android.content.Context
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.example.defenseapplication.databinding.LiveVideoActivityBinding
class LiveVideoActivity : AppCompatActivity() {
private lateinit var binding: LiveVideoActivityBinding
private var isVoiceEnabled = false
private var isLightOn = false
private var isRecording = false
private var recordTime = 0
private var recordHandler: Handler? = null
private var recordRunnable: Runnable? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = LiveVideoActivityBinding.inflate(layoutInflater)
setContentView(binding.root)
initListener()
}
private fun initListener() {
// 返回按钮
binding.btnBack.setOnClickListener {
finish()
}
// 菜单按钮
binding.ivMenu.setOnClickListener {
Toast.makeText(this, "菜单", Toast.LENGTH_SHORT).show()
}
// 全屏按钮
binding.ivFullscreen.setOnClickListener {
Toast.makeText(this, "全屏", Toast.LENGTH_SHORT).show()
}
// 语音按钮
binding.llVoice.setOnClickListener {
toggleVoice()
}
// 灯光按钮
binding.llLight.setOnClickListener {
toggleLight()
}
// 录像按钮
binding.llRecord.setOnClickListener {
toggleRecording()
}
// 告警日志区域
binding.llAlarmLog.setOnClickListener {
Toast.makeText(this, "查看告警日志", Toast.LENGTH_SHORT).show()
}
}
private fun toggleVoice() {
isVoiceEnabled = !isVoiceEnabled
if (isVoiceEnabled) {
binding.vVoiceActive.visibility = View.VISIBLE
binding.ivVoice.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.green))
Toast.makeText(this, "语音已开启", Toast.LENGTH_SHORT).show()
} else {
binding.vVoiceActive.visibility = View.INVISIBLE
binding.ivVoice.clearColorFilter()
Toast.makeText(this, "语音已关闭", Toast.LENGTH_SHORT).show()
}
}
private fun toggleLight() {
isLightOn = !isLightOn
if (isLightOn) {
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.light_on)
binding.ivLight.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.green))
Toast.makeText(this, "灯光已开启", Toast.LENGTH_SHORT).show()
} else {
binding.ivLight.setImageResource(com.example.defenseapplication.R.drawable.low_light)
binding.ivLight.clearColorFilter()
Toast.makeText(this, "灯光已关闭", Toast.LENGTH_SHORT).show()
}
}
private fun toggleRecording() {
isRecording = !isRecording
if (isRecording) {
recordTime = 0
binding.tvRecordTime.text = "00"
startRecordTimer()
binding.ivRecord.setColorFilter(resources.getColor(com.example.defenseapplication.R.color.red))
Toast.makeText(this, "开始录像", Toast.LENGTH_SHORT).show()
} else {
stopRecordTimer()
binding.ivRecord.clearColorFilter()
Toast.makeText(this, "停止录像,共录制 ${recordTime}", Toast.LENGTH_SHORT).show()
}
}
private fun startRecordTimer() {
recordHandler = Handler(Looper.getMainLooper())
recordRunnable = object : Runnable {
override fun run() {
recordTime++
binding.tvRecordTime.text = String.format("%02d", recordTime)
recordHandler?.postDelayed(this, 1000)
}
}
recordHandler?.post(recordRunnable!!)
}
private fun stopRecordTimer() {
recordRunnable?.let { recordHandler?.removeCallbacks(it) }
recordHandler = null
recordRunnable = null
}
override fun onDestroy() {
super.onDestroy()
stopRecordTimer()
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

View File

@@ -0,0 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="#4DFFFFFF" />
</shape>

View File

@@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="1dp"
android:color="@color/green" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="3dp"
android:color="@color/green"
android:bottom="3dp"
android:left="3dp"
android:right="0dp"
android:top="0dp" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="3dp"
android:color="@color/green"
android:bottom="3dp"
android:left="0dp"
android:right="3dp"
android:top="0dp" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="3dp"
android:color="@color/green"
android:bottom="0dp"
android:left="3dp"
android:right="0dp"
android:top="3dp" />
</shape>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android">
<solid android:color="@android:color/transparent" />
<stroke
android:width="3dp"
android:color="@color/green"
android:bottom="0dp"
android:left="0dp"
android:right="3dp"
android:top="3dp" />
</shape>

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 641 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 661 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 740 B

View File

@@ -0,0 +1,342 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#F5F6F6"
android:orientation="vertical">
<!-- 顶部导航栏 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="56dp"
android:background="#FFFFFF"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<Button
android:id="@+id/btnBack"
android:layout_width="24dp"
android:layout_height="24dp"
android:background="@drawable/back"
android:contentDescription="返回" />
<TextView
android:id="@+id/tvTitle"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:text="智能防御机A1"
android:textColor="#000000"
android:textSize="18sp" />
<ImageView
android:id="@+id/ivMenu"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/settings" />
</LinearLayout>
<!-- 视频流信息 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="32dp"
android:background="#FFFFFF"
android:gravity="center_vertical"
android:orientation="horizontal"
android:paddingLeft="16dp"
android:paddingRight="16dp">
<TextView
android:id="@+id/tvBitRate"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:text="120 B/S"
android:textColor="#999999"
android:textSize="14sp" />
</LinearLayout>
<!-- 视频显示区域 -->
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="280dp"
android:background="#000000">
<ImageView
android:id="@+id/ivVideo"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/img" />
<!-- 全屏按钮 -->
<ImageView
android:id="@+id/ivFullscreen"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:layout_margin="16dp"
android:src="@drawable/go_up" />
</RelativeLayout>
<!-- 功能按钮区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="120dp"
android:background="#FFFFFF"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/llVoice"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<ImageView
android:id="@+id/ivVoice"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:src="@drawable/voice" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<ImageView
android:id="@+id/ivLight"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:src="@drawable/light_on" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center">
<ImageView
android:id="@+id/ivRecord"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_centerInParent="true"
android:src="@drawable/copy" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
<!-- 告警日志区域 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginTop="16dp"
android:layout_marginRight="16dp"
android:layout_marginBottom="16dp"
android:background="#FFFFFF">
<LinearLayout
android:id="@+id/llAlarmLog"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:padding="16dp">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:orientation="horizontal">
<TextView
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="告警日志"
android:textColor="#000000"
android:textSize="16sp"
android:textStyle="bold" />
<ImageView
android:layout_width="16dp"
android:layout_height="16dp"
android:src="@drawable/go_up" />
</LinearLayout>
<!-- 告警图片列表 -->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingRight="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/img" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:background="#000000"
android:padding="2dp"
android:text="60s"
android:textColor="#FFFFFF"
android:textSize="10sp" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="入侵告警"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="03-11"
android:textColor="#999999"
android:textSize="10sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="4dp"
android:paddingRight="4dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/img" />
<ImageView
android:layout_width="20dp"
android:layout_height="20dp"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:src="@drawable/copy" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="入侵告警"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="03-11"
android:textColor="#999999"
android:textSize="10sp" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="vertical"
android:paddingLeft="8dp">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="80dp">
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:scaleType="centerCrop"
android:src="@drawable/img" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_alignParentBottom="true"
android:background="#000000"
android:padding="2dp"
android:text="60s"
android:textColor="#FFFFFF"
android:textSize="10sp" />
</RelativeLayout>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="入侵告警"
android:textColor="#666666"
android:textSize="12sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="03-11"
android:textColor="#999999"
android:textSize="10sp" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>
</LinearLayout>

View File

@@ -0,0 +1,176 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@color/black">
<SurfaceView
android:id="@+id/surfaceView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#B2000000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#B2000000" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<LinearLayout
android:layout_width="0dp"
android:layout_height="250dp"
android:layout_weight="1"
android:background="#B2000000" />
<FrameLayout
android:layout_width="250dp"
android:layout_height="250dp">
<View
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="@drawable/bg_scan_frame" />
<View
android:id="@+id/scanLine"
android:layout_width="match_parent"
android:layout_height="2dp"
android:background="@color/green" />
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/corner_top_left"
android:layout_gravity="top|left" />
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/corner_top_right"
android:layout_gravity="top|right" />
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/corner_bottom_left"
android:layout_gravity="bottom|left" />
<View
android:layout_width="16dp"
android:layout_height="16dp"
android:background="@drawable/corner_bottom_right"
android:layout_gravity="bottom|right" />
</FrameLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="250dp"
android:layout_weight="1"
android:background="#B2000000" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:background="#B2000000" />
</LinearLayout>
<Button
android:id="@+id/btnBack"
android:layout_width="24dp"
android:layout_height="24dp"
android:layout_marginTop="40dp"
android:layout_marginLeft="16dp"
android:background="@drawable/back2"
android:contentDescription="返回" />
<TextView
android:id="@+id/tvScanTip"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="550dp"
android:text="请扫描设备或说明书上的二维码"
android:textColor="@color/white"
android:textSize="14sp" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="80dp"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/llAlbum"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginRight="80dp"
android:background="@drawable/bg_button_circle"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/ivAlbum"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/album" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="相册"
android:textColor="@color/white"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/llFlashlight"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_marginLeft="80dp"
android:background="@drawable/bg_button_circle"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/ivFlashlight"
android:layout_width="24dp"
android:layout_height="24dp"
android:src="@drawable/flashlight" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="4dp"
android:text="手电筒"
android:textColor="@color/white"
android:textSize="12dp" />
</LinearLayout>
</LinearLayout>
</RelativeLayout>