更新二维码扫码

pull/840/head
gedoor 4 years ago
parent 5e1f106d1b
commit d7a7f35bd7
  1. 2
      app/build.gradle
  2. 74
      app/src/main/java/io/legado/app/ui/qrcode/QrCodeActivity.kt
  3. 13
      app/src/main/java/io/legado/app/ui/qrcode/QrCodeFragment.kt
  4. 29
      app/src/main/java/io/legado/app/utils/BitmapUtils.kt
  5. 7
      app/src/main/java/io/legado/app/utils/ContextExtensions.kt
  6. 467
      app/src/main/java/io/legado/app/utils/QRCodeUtils.kt
  7. 76
      app/src/main/res/layout/activity_qrcode_capture.xml

@ -185,7 +185,7 @@ dependencies {
implementation 'org.nanohttpd:nanohttpd-websocket:2.3.1'
//
implementation 'cn.bingoogolapple:bga-qrcode-zxing:1.3.7'
implementation 'com.king.zxing:zxing-lite:2.0.2'
//
implementation 'com.jaredrummler:colorpicker:1.1.0'

@ -6,36 +6,29 @@ import android.graphics.BitmapFactory
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import android.view.View
import cn.bingoogolapple.qrcode.core.QRCodeView
import com.google.zxing.Result
import com.king.zxing.CameraScan.OnScanResultCallback
import io.legado.app.R
import io.legado.app.base.BaseActivity
import io.legado.app.databinding.ActivityQrcodeCaptureBinding
import io.legado.app.help.permission.Permissions
import io.legado.app.help.permission.PermissionsCompat
import io.legado.app.utils.QRCodeUtils
import io.legado.app.utils.readBytes
import org.jetbrains.anko.toast
class QrCodeActivity : BaseActivity<ActivityQrcodeCaptureBinding>(), QRCodeView.Delegate {
class QrCodeActivity : BaseActivity<ActivityQrcodeCaptureBinding>(), OnScanResultCallback {
private val requestQrImage = 202
private var flashlightIsOpen: Boolean = false
override fun getViewBinding(): ActivityQrcodeCaptureBinding {
return ActivityQrcodeCaptureBinding.inflate(layoutInflater)
}
override fun onActivityCreated(savedInstanceState: Bundle?) {
binding.zXingView.setDelegate(this)
binding.fabFlashlight.setOnClickListener {
if (flashlightIsOpen) {
flashlightIsOpen = false
binding.zXingView.closeFlashlight()
} else {
flashlightIsOpen = true
binding.zXingView.openFlashlight()
}
}
val fTag = "qrCodeFragment"
var qrCodeFragment = supportFragmentManager.findFragmentByTag(fTag)
if (qrCodeFragment == null) qrCodeFragment = QrCodeFragment()
supportFragmentManager.beginTransaction()
.replace(R.id.fl_content, qrCodeFragment, fTag)
.commit()
}
override fun onCompatCreateOptionsMenu(menu: Menu): Boolean {
@ -55,60 +48,21 @@ class QrCodeActivity : BaseActivity<ActivityQrcodeCaptureBinding>(), QRCodeView.
return super.onCompatOptionsItemSelected(item)
}
override fun onStart() {
super.onStart()
startCamera()
}
private fun startCamera() {
PermissionsCompat.Builder(this)
.addPermissions(*Permissions.Group.CAMERA)
.rationale(R.string.qr_per)
.onGranted {
binding.zXingView.visibility = View.VISIBLE
//TODO 显示扫描框,并开始识别
binding.zXingView.startSpotAndShowRect()
}.request()
}
override fun onStop() {
//TODO 关闭摄像头预览,并且隐藏扫描框
binding.zXingView.stopCamera()
super.onStop()
}
override fun onDestroy() {
//TODO 销毁二维码扫描控件
binding.zXingView.onDestroy()
super.onDestroy()
}
override fun onScanQRCodeSuccess(result: String) {
override fun onScanResultCallback(result: Result?): Boolean {
val intent = Intent()
intent.putExtra("result", result)
intent.putExtra("result", result?.text)
setResult(RESULT_OK, intent)
finish()
}
override fun onCameraAmbientBrightnessChanged(isDark: Boolean) {
}
override fun onScanQRCodeOpenCameraError() {
toast("打开相机失败")
return true
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
data?.data?.let {
//TODO 显示扫描框,并开始识别
binding.zXingView.startSpotAndShowRect()
if (resultCode == Activity.RESULT_OK && requestCode == requestQrImage) {
// 本来就用到 QRCodeView 时可直接调 QRCodeView 的方法,走通用的回调
it.readBytes(this)?.let { bytes ->
val bitmap = BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
binding.zXingView.decodeQRCode(bitmap)
onScanResultCallback(QRCodeUtils.parseCodeResult(bitmap))
}
}
}

@ -0,0 +1,13 @@
package io.legado.app.ui.qrcode
import com.google.zxing.Result
import com.king.zxing.CaptureFragment
class QrCodeFragment : CaptureFragment() {
override fun onScanResultCallback(result: Result?): Boolean {
(activity as? QrCodeActivity)?.onScanResultCallback(result)
return true
}
}

@ -1,11 +1,8 @@
package io.legado.app.utils
import android.content.Context
import android.graphics.Bitmap
import android.graphics.*
import android.graphics.Bitmap.Config
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.renderscript.Allocation
import android.renderscript.Element
import android.renderscript.RenderScript
@ -221,6 +218,30 @@ object BitmapUtils {
}
}
fun changeBitmapSize(bitmap: Bitmap, newWidth: Int, newHeight: Int): Bitmap {
val width = bitmap.width
val height = bitmap.height
//计算压缩的比率
var scaleWidth = newWidth.toFloat() / width
var scaleHeight = newHeight.toFloat() / height
if (scaleWidth > scaleHeight) {
scaleWidth = scaleHeight
} else {
scaleHeight = scaleWidth
}
//获取想要缩放的matrix
val matrix = Matrix()
matrix.postScale(scaleWidth, scaleHeight)
//获取新的bitmap
return Bitmap.createBitmap(bitmap, 0, 0, width, height, matrix, true)
}
/**
* 高斯模糊
*/

@ -18,9 +18,6 @@ import androidx.annotation.StringRes
import androidx.core.content.ContextCompat
import androidx.core.content.FileProvider
import androidx.core.content.edit
import cn.bingoogolapple.qrcode.zxing.QRCodeEncoder
import com.google.zxing.EncodeHintType
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import io.legado.app.BuildConfig
import io.legado.app.R
import org.jetbrains.anko.defaultSharedPreferences
@ -104,9 +101,7 @@ val Context.navigationBarHeight: Int
@SuppressLint("SetWorldReadable")
fun Context.shareWithQr(title: String, text: String) {
QRCodeEncoder.HINTS[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.L
val bitmap = QRCodeEncoder.syncEncodeQRCode(text, 600)
QRCodeEncoder.HINTS[EncodeHintType.ERROR_CORRECTION] = ErrorCorrectionLevel.H
val bitmap = QRCodeUtils.createQRCode(text)
if (bitmap == null) {
toast(R.string.text_too_long_qr_error)
} else {

@ -0,0 +1,467 @@
package io.legado.app.utils
import android.graphics.*
import android.text.TextPaint
import android.text.TextUtils
import androidx.annotation.ColorInt
import androidx.annotation.FloatRange
import com.google.zxing.*
import com.google.zxing.common.GlobalHistogramBinarizer
import com.google.zxing.common.HybridBinarizer
import com.google.zxing.qrcode.QRCodeWriter
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import com.king.zxing.DecodeFormatManager
import com.king.zxing.util.LogUtils
import java.util.*
import kotlin.math.max
@Suppress("MemberVisibilityCanBePrivate", "unused")
object QRCodeUtils {
const val DEFAULT_REQ_WIDTH = 480
const val DEFAULT_REQ_HEIGHT = 640
/**
* 生成二维码
* @param content 二维码的内容
* @param heightPix 二维码的高
* @param logo 二维码中间的logo
* @param ratio logo所占比例 因为二维码的最大容错率为30%所以建议ratio的范围小于0.3
* @return
*/
fun createQRCode(
content: String,
heightPix: Int = DEFAULT_REQ_HEIGHT,
logo: Bitmap? = null,
@FloatRange(from = 0.0, to = 1.0) ratio: Float = 0.2f,
errorCorrectionLevel: ErrorCorrectionLevel = ErrorCorrectionLevel.H
): Bitmap? {
//配置参数
val hints: MutableMap<EncodeHintType, Any> = EnumMap(EncodeHintType::class.java)
hints[EncodeHintType.CHARACTER_SET] = "utf-8"
//容错级别
hints[EncodeHintType.ERROR_CORRECTION] = errorCorrectionLevel
//设置空白边距的宽度
hints[EncodeHintType.MARGIN] = 1 //default is 4
return createQRCode(content, heightPix, logo, ratio, hints)
}
/**
* 生成二维码
* @param content 二维码的内容
* @param heightPix 二维码的高
* @param logo 二维码中间的logo
* @param ratio logo所占比例 因为二维码的最大容错率为30%所以建议ratio的范围小于0.3
* @param hints
* @param codeColor 二维码的颜色
* @return
*/
fun createQRCode(
content: String?,
heightPix: Int,
logo: Bitmap?,
@FloatRange(from = 0.0, to = 1.0) ratio: Float = 0.2f,
hints: Map<EncodeHintType, *>,
codeColor: Int = Color.BLACK
): Bitmap? {
try {
// 图像数据转换,使用了矩阵转换
val bitMatrix =
QRCodeWriter().encode(content, BarcodeFormat.QR_CODE, heightPix, heightPix, hints)
val pixels = IntArray(heightPix * heightPix)
// 下面这里按照二维码的算法,逐个生成二维码的图片,
// 两个for循环是图片横列扫描的结果
for (y in 0 until heightPix) {
for (x in 0 until heightPix) {
if (bitMatrix[x, y]) {
pixels[y * heightPix + x] = codeColor
} else {
pixels[y * heightPix + x] = Color.WHITE
}
}
}
// 生成二维码图片的格式
var bitmap = Bitmap.createBitmap(heightPix, heightPix, Bitmap.Config.ARGB_8888)
bitmap!!.setPixels(pixels, 0, heightPix, 0, 0, heightPix, heightPix)
if (logo != null) {
bitmap = addLogo(bitmap, logo, ratio)
}
return bitmap
} catch (e: WriterException) {
LogUtils.w(e.message)
}
return null
}
/**
* 在二维码中间添加Logo图案
* @param src
* @param logo
* @param ratio logo所占比例 因为二维码的最大容错率为30%所以建议ratio的范围小于0.3
* @return
*/
private fun addLogo(
src: Bitmap?,
logo: Bitmap?,
@FloatRange(from = 0.0, to = 1.0) ratio: Float
): Bitmap? {
if (src == null) {
return null
}
if (logo == null) {
return src
}
//获取图片的宽高
val srcWidth = src.width
val srcHeight = src.height
val logoWidth = logo.width
val logoHeight = logo.height
if (srcWidth == 0 || srcHeight == 0) {
return null
}
if (logoWidth == 0 || logoHeight == 0) {
return src
}
//logo大小为二维码整体大小
val scaleFactor = srcWidth * ratio / logoWidth
var bitmap = Bitmap.createBitmap(srcWidth, srcHeight, Bitmap.Config.ARGB_8888)
try {
val canvas = Canvas(bitmap!!)
canvas.drawBitmap(src, 0f, 0f, null)
canvas.scale(
scaleFactor,
scaleFactor,
(srcWidth / 2).toFloat(),
(srcHeight / 2).toFloat()
)
canvas.drawBitmap(
logo,
((srcWidth - logoWidth) / 2).toFloat(),
((srcHeight - logoHeight) / 2).toFloat(),
null
)
canvas.save()
canvas.restore()
} catch (e: Exception) {
bitmap = null
LogUtils.w(e.message)
}
return bitmap
}
/**
* 解析一维码/二维码图片
* @param bitmap 解析的图片
* @param hints 解析编码类型
* @return
*/
fun parseCode(
bitmap: Bitmap,
reqWidth: Int = DEFAULT_REQ_WIDTH,
reqHeight: Int = DEFAULT_REQ_HEIGHT,
hints: Map<DecodeHintType?, Any?> = DecodeFormatManager.ALL_HINTS
): String? {
val result = parseCodeResult(bitmap, reqWidth, reqHeight, hints)
return result?.text
}
/**
* 解析一维码/二维码图片
* @param bitmap 解析的图片
* @param hints 解析编码类型
* @return
*/
fun parseCodeResult(
bitmap: Bitmap,
reqWidth: Int = DEFAULT_REQ_WIDTH,
reqHeight: Int = DEFAULT_REQ_HEIGHT,
hints: Map<DecodeHintType?, Any?> = DecodeFormatManager.ALL_HINTS
): Result? {
if (bitmap.width > reqWidth || bitmap.height > reqHeight) {
val bm = BitmapUtils.changeBitmapSize(bitmap, reqWidth, reqHeight)
return parseCodeResult(getRGBLuminanceSource(bm), hints)
}
return parseCodeResult(getRGBLuminanceSource(bitmap), hints)
}
/**
* 解析一维码/二维码图片
* @param source
* @param hints
* @return
*/
fun parseCodeResult(source: LuminanceSource?, hints: Map<DecodeHintType?, Any?>?): Result? {
var result: Result? = null
val reader = MultiFormatReader()
try {
reader.setHints(hints)
if (source != null) {
result = decodeInternal(reader, source)
if (result == null) {
result = decodeInternal(reader, source.invert())
}
if (result == null && source.isRotateSupported) {
result = decodeInternal(reader, source.rotateCounterClockwise())
}
}
} catch (e: java.lang.Exception) {
LogUtils.w(e.message)
} finally {
reader.reset()
}
return result
}
/**
* 解析二维码图片
* @param bitmapPath 需要解析的图片路径
* @return
*/
fun parseQRCode(bitmapPath: String?): String? {
val result = parseQRCodeResult(bitmapPath)
return result?.text
}
/**
* 解析二维码图片
* @param bitmapPath 需要解析的图片路径
* @param reqWidth 请求目标宽度如果实际图片宽度大于此值会自动进行压缩处理 reqWidth reqHeight都小于或等于0时则不进行压缩处理
* @param reqHeight 请求目标高度如果实际图片高度大于此值会自动进行压缩处理 reqWidth reqHeight都小于或等于0时则不进行压缩处理
* @return
*/
fun parseQRCodeResult(
bitmapPath: String?,
reqWidth: Int = DEFAULT_REQ_WIDTH,
reqHeight: Int = DEFAULT_REQ_HEIGHT
): Result? {
return parseCodeResult(bitmapPath, reqWidth, reqHeight, DecodeFormatManager.QR_CODE_HINTS)
}
/**
* 解析一维码/二维码图片
* @param bitmapPath 需要解析的图片路径
* @return
*/
fun parseCode(
bitmapPath: String?,
reqWidth: Int = DEFAULT_REQ_WIDTH,
reqHeight: Int = DEFAULT_REQ_HEIGHT,
hints: Map<DecodeHintType?, Any?> = DecodeFormatManager.ALL_HINTS
): String? {
return parseCodeResult(bitmapPath, reqWidth, reqHeight, hints)?.text
}
/**
* 解析一维码/二维码图片
* @param bitmapPath 需要解析的图片路径
* @param reqWidth 请求目标宽度如果实际图片宽度大于此值会自动进行压缩处理 reqWidth reqHeight都小于或等于0时则不进行压缩处理
* @param reqHeight 请求目标高度如果实际图片高度大于此值会自动进行压缩处理 reqWidth reqHeight都小于或等于0时则不进行压缩处理
* @param hints 解析编码类型
* @return
*/
fun parseCodeResult(
bitmapPath: String?,
reqWidth: Int = DEFAULT_REQ_WIDTH,
reqHeight: Int = DEFAULT_REQ_HEIGHT,
hints: Map<DecodeHintType?, Any?> = DecodeFormatManager.ALL_HINTS
): Result? {
var result: Result? = null
val reader = MultiFormatReader()
try {
reader.setHints(hints)
val source = getRGBLuminanceSource(compressBitmap(bitmapPath, reqWidth, reqHeight))
result = decodeInternal(reader, source)
if (result == null) {
result = decodeInternal(reader, source.invert())
}
if (result == null && source.isRotateSupported) {
result = decodeInternal(reader, source.rotateCounterClockwise())
}
} catch (e: Exception) {
LogUtils.w(e.message)
} finally {
reader.reset()
}
return result
}
private fun decodeInternal(reader: MultiFormatReader, source: LuminanceSource): Result? {
var result: Result? = null
try {
try {
//采用HybridBinarizer解析
result = reader.decodeWithState(BinaryBitmap(HybridBinarizer(source)))
} catch (e: Exception) {
}
if (result == null) {
//如果没有解析成功,再采用GlobalHistogramBinarizer解析一次
result = reader.decodeWithState(BinaryBitmap(GlobalHistogramBinarizer(source)))
}
} catch (e: Exception) {
}
return result
}
/**
* 压缩图片
* @param path
* @return
*/
private fun compressBitmap(path: String?, reqWidth: Int, reqHeight: Int): Bitmap {
if (reqWidth > 0 && reqHeight > 0) { //都大于进行判断是否压缩
val newOpts = BitmapFactory.Options()
// 开始读入图片,此时把options.inJustDecodeBounds 设回true了
newOpts.inJustDecodeBounds = true //获取原始图片大小
BitmapFactory.decodeFile(path, newOpts) // 此时返回bm为空
val width = newOpts.outWidth.toFloat()
val height = newOpts.outHeight.toFloat()
// 缩放比,由于是固定比例缩放,只用高或者宽其中一个数据进行计算即可
var wSize = 1 // wSize=1表示不缩放
if (width > reqWidth) { // 如果宽度大的话根据宽度固定大小缩放
wSize = (width / reqWidth).toInt()
}
var hSize = 1 // wSize=1表示不缩放
if (height > reqHeight) { // 如果高度高的话根据宽度固定大小缩放
hSize = (height / reqHeight).toInt()
}
var size = max(wSize, hSize)
if (size <= 0) size = 1
newOpts.inSampleSize = size // 设置缩放比例
// 重新读入图片,注意此时已经把options.inJustDecodeBounds 设回false了
newOpts.inJustDecodeBounds = false
return BitmapFactory.decodeFile(path, newOpts)
}
return BitmapFactory.decodeFile(path)
}
/**
* 获取RGBLuminanceSource
* @param bitmap
* @return
*/
private fun getRGBLuminanceSource(bitmap: Bitmap): RGBLuminanceSource {
val width = bitmap.width
val height = bitmap.height
val pixels = IntArray(width * height)
bitmap.getPixels(pixels, 0, bitmap.width, 0, 0, bitmap.width, bitmap.height)
return RGBLuminanceSource(width, height, pixels)
}
/**
* 生成条形码
* @param content
* @param format
* @param desiredWidth
* @param desiredHeight
* @param hints
* @param isShowText
* @param textSize
* @param codeColor
* @return
*/
fun createBarCode(
content: String?,
desiredWidth: Int,
desiredHeight: Int,
format: BarcodeFormat = BarcodeFormat.CODE_128,
hints: Map<EncodeHintType?, *>? = null,
isShowText: Boolean = true,
textSize: Int = 40,
@ColorInt codeColor: Int = Color.BLACK
): Bitmap? {
if (TextUtils.isEmpty(content)) {
return null
}
val writer = MultiFormatWriter()
try {
val result = writer.encode(
content, format, desiredWidth,
desiredHeight, hints
)
val width = result.width
val height = result.height
val pixels = IntArray(width * height)
// All are 0, or black, by default
for (y in 0 until height) {
val offset = y * width
for (x in 0 until width) {
pixels[offset + x] = if (result[x, y]) codeColor else Color.WHITE
}
}
val bitmap = Bitmap.createBitmap(
width, height,
Bitmap.Config.ARGB_8888
)
bitmap.setPixels(pixels, 0, width, 0, 0, width, height)
return if (isShowText) {
addCode(bitmap, content, textSize, codeColor, textSize / 2)
} else bitmap
} catch (e: WriterException) {
LogUtils.w(e.message)
}
return null
}
/**
* 条形码下面添加文本信息
* @param src
* @param code
* @param textSize
* @param textColor
* @return
*/
private fun addCode(
src: Bitmap?,
code: String?,
textSize: Int,
@ColorInt textColor: Int,
offset: Int
): Bitmap? {
if (src == null) {
return null
}
if (TextUtils.isEmpty(code)) {
return src
}
//获取图片的宽高
val srcWidth = src.width
val srcHeight = src.height
if (srcWidth <= 0 || srcHeight <= 0) {
return null
}
var bitmap = Bitmap.createBitmap(
srcWidth,
srcHeight + textSize + offset * 2,
Bitmap.Config.ARGB_8888
)
try {
val canvas = Canvas(bitmap!!)
canvas.drawBitmap(src, 0f, 0f, null)
val paint = TextPaint()
paint.textSize = textSize.toFloat()
paint.color = textColor
paint.textAlign = Paint.Align.CENTER
canvas.drawText(
code!!,
(srcWidth / 2).toFloat(),
(srcHeight + textSize / 2 + offset).toFloat(),
paint
)
canvas.save()
canvas.restore()
} catch (e: Exception) {
bitmap = null
LogUtils.w(e.message)
}
return bitmap
}
}

@ -1,45 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
<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">
<cn.bingoogolapple.qrcode.zxing.ZXingView
android:id="@+id/z_xing_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone"
app:qrcv_animTime="1000"
app:qrcv_barCodeTipText="将条码放入框内,即可自动扫描"
app:qrcv_barcodeRectHeight="120dp"
app:qrcv_borderColor="@android:color/white"
app:qrcv_borderSize="1dp"
app:qrcv_cornerColor="@color/primaryDark"
app:qrcv_cornerDisplayType="center"
app:qrcv_cornerLength="20dp"
app:qrcv_cornerSize="3dp"
app:qrcv_isAutoZoom="true"
app:qrcv_isBarcode="false"
app:qrcv_isOnlyDecodeScanBoxArea="false"
app:qrcv_isScanLineReverse="true"
app:qrcv_isShowDefaultGridScanLineDrawable="false"
app:qrcv_isShowDefaultScanLineDrawable="true"
app:qrcv_isShowLocationPoint="true"
app:qrcv_isShowTipBackground="true"
app:qrcv_isShowTipTextAsSingleLine="false"
app:qrcv_isTipTextBelowRect="false"
app:qrcv_maskColor="#33FFFFFF"
app:qrcv_qrCodeTipText="将二维码放入框内,即可自动扫描"
app:qrcv_rectWidth="300dp"
app:qrcv_scanLineColor="@color/primaryDark"
app:qrcv_scanLineMargin="0dp"
app:qrcv_scanLineSize="0.5dp"
app:qrcv_tipTextColor="@android:color/white"
app:qrcv_tipTextSize="12sp"
app:qrcv_toolbarHeight="?attr/actionBarSize"
app:qrcv_topOffset="100dp"
app:qrcv_verticalBias="-1" />
android:layout_height="match_parent"
android:orientation="vertical">
<io.legado.app.ui.widget.TitleBar
android:id="@+id/title_bar"
@ -47,35 +11,9 @@
android:layout_height="wrap_content"
app:title="@string/scan_qr_code" />
<LinearLayout
<FrameLayout
android:id="@+id/fl_content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentStart="true"
android:layout_alignParentBottom="true"
android:padding="16dp">
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fab_flashlight"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:contentDescription="@string/read_aloud"
android:src="@drawable/ic_daytime"
android:tint="@color/primaryText"
app:backgroundTint="@color/background_menu"
app:elevation="2dp"
app:fabSize="mini"
app:pressedTranslationZ="2dp" />
<Space
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1" />
android:layout_height="match_parent" />
</LinearLayout>
</RelativeLayout>
</LinearLayout>
Loading…
Cancel
Save