Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
weixin_41840029
PaddleOCR
提交
ec903eb5
P
PaddleOCR
项目概览
weixin_41840029
/
PaddleOCR
与 Fork 源项目一致
Fork自
PaddlePaddle / PaddleOCR
通知
1
Star
1
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
P
PaddleOCR
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
提交
Issue看板
未验证
提交
ec903eb5
编写于
8月 06, 2020
作者:
X
xiaoting
提交者:
GitHub
8月 06, 2020
浏览文件
操作
浏览文件
下载
差异文件
Merge pull request #492 from authorfu/develop
mini demo modification
上级
57e0565a
c3785440
变更
14
显示空白变更内容
内联
并排
Showing
14 changed file
with
262 addition
and
51 deletion
+262
-51
deploy/android_demo/app/build.gradle
deploy/android_demo/app/build.gradle
+5
-6
deploy/android_demo/app/src/main/AndroidManifest.xml
deploy/android_demo/app/src/main/AndroidManifest.xml
+2
-2
deploy/android_demo/app/src/main/cpp/native.cpp
deploy/android_demo/app/src/main/cpp/native.cpp
+1
-1
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.cpp
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.cpp
+1
-1
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.h
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.h
+12
-12
deploy/android_demo/app/src/main/cpp/ppredictor.h
deploy/android_demo/app/src/main/cpp/ppredictor.h
+4
-4
deploy/android_demo/app/src/main/cpp/predictor_output.h
deploy/android_demo/app/src/main/cpp/predictor_output.h
+4
-4
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/AppCompatPreferenceActivity.java
...idu/paddle/lite/demo/ocr/AppCompatPreferenceActivity.java
+6
-5
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java
...ain/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java
+6
-5
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MiniActivity.java
...ain/java/com/baidu/paddle/lite/demo/ocr/MiniActivity.java
+157
-0
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java
...c/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java
+14
-8
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/SettingsActivity.java
...java/com/baidu/paddle/lite/demo/ocr/SettingsActivity.java
+2
-1
deploy/android_demo/app/src/main/res/layout/activity_main.xml
...oy/android_demo/app/src/main/res/layout/activity_main.xml
+2
-2
deploy/android_demo/app/src/main/res/layout/activity_mini.xml
...oy/android_demo/app/src/main/res/layout/activity_mini.xml
+46
-0
未找到文件。
deploy/android_demo/app/build.gradle
浏览文件 @
ec903eb5
...
...
@@ -3,11 +3,11 @@ import java.security.MessageDigest
apply
plugin:
'com.android.application'
android
{
compileSdkVersion
2
8
compileSdkVersion
2
9
defaultConfig
{
applicationId
"com.baidu.paddle.lite.demo.ocr"
minSdkVersion
15
targetSdkVersion
2
8
minSdkVersion
23
targetSdkVersion
2
9
versionCode
1
versionName
"1.0"
testInstrumentationRunner
"android.support.test.runner.AndroidJUnitRunner"
...
...
@@ -39,9 +39,8 @@ android {
dependencies
{
implementation
fileTree
(
include:
[
'*.jar'
],
dir:
'libs'
)
implementation
'com.android.support:appcompat-v7:28.0.0'
implementation
'com.android.support.constraint:constraint-layout:1.1.3'
implementation
'com.android.support:design:28.0.0'
implementation
'androidx.appcompat:appcompat:1.1.0'
implementation
'androidx.constraintlayout:constraintlayout:1.1.3'
testImplementation
'junit:junit:4.12'
androidTestImplementation
'com.android.support.test:runner:1.0.2'
androidTestImplementation
'com.android.support.test.espresso:espresso-core:3.0.2'
...
...
deploy/android_demo/app/src/main/AndroidManifest.xml
浏览文件 @
ec903eb5
...
...
@@ -14,10 +14,10 @@
android:roundIcon=
"@mipmap/ic_launcher_round"
android:supportsRtl=
"true"
android:theme=
"@style/AppTheme"
>
<!-- to test MiniActivity, change this to com.baidu.paddle.lite.demo.ocr.MiniActivity -->
<activity
android:name=
"com.baidu.paddle.lite.demo.ocr.MainActivity"
>
<intent-filter>
<action
android:name=
"android.intent.action.MAIN"
/>
<category
android:name=
"android.intent.category.LAUNCHER"
/>
</intent-filter>
</activity>
...
...
@@ -26,7 +26,7 @@
android:label=
"Settings"
>
</activity>
<provider
android:name=
"android
.support.v4
.content.FileProvider"
android:name=
"android
x.core
.content.FileProvider"
android:authorities=
"com.baidu.paddle.lite.demo.ocr.fileprovider"
android:exported=
"false"
android:grantUriPermissions=
"true"
>
...
...
deploy/android_demo/app/src/main/cpp/native.cpp
浏览文件 @
ec903eb5
...
...
@@ -30,7 +30,7 @@ Java_com_baidu_paddle_lite_demo_ocr_OCRPredictorNative_init(JNIEnv *env, jobject
}
/**
* "LITE_POWER_HIGH"
转为
paddle::lite_api::LITE_POWER_HIGH
* "LITE_POWER_HIGH"
convert to
paddle::lite_api::LITE_POWER_HIGH
* @param cpu_mode
* @return
*/
...
...
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.cpp
浏览文件 @
ec903eb5
...
...
@@ -37,7 +37,7 @@ int OCR_PPredictor::init_from_file(const std::string &det_model_path, const std:
return
RETURN_OK
;
}
/**
*
调试用,保存第一步的框选结果
*
for debug use, show result of First Step
* @param filter_boxes
* @param boxes
* @param srcimg
...
...
deploy/android_demo/app/src/main/cpp/ocr_ppredictor.h
浏览文件 @
ec903eb5
...
...
@@ -12,26 +12,26 @@
namespace
ppredictor
{
/**
*
配置
*
Config
*/
struct
OCR_Config
{
int
thread_num
=
4
;
//
线程数
int
thread_num
=
4
;
//
Thread num
paddle
::
lite_api
::
PowerMode
mode
=
paddle
::
lite_api
::
LITE_POWER_HIGH
;
// PaddleLite Mode
};
/**
*
一个四边形内图片的推理结果,
*
PolyGone Result
*/
struct
OCRPredictResult
{
std
::
vector
<
int
>
word_index
;
//
std
::
vector
<
int
>
word_index
;
std
::
vector
<
std
::
vector
<
int
>>
points
;
float
score
;
};
/**
* OCR
一共有2个模型进行推理,
* 1.
使用第一个模型(det),框选出多个四边形
* 2.
从原图从抠出这些多边形,使用第二个模型(rec),获取文本
* OCR
there are 2 models
* 1.
First model(det),select polygones to show where are the texts
* 2.
crop from the origin images, use these polygones to infer
*/
class
OCR_PPredictor
:
public
PPredictor_Interface
{
public:
...
...
@@ -50,7 +50,7 @@ public:
int
init
(
const
std
::
string
&
det_model_content
,
const
std
::
string
&
rec_model_content
);
int
init_from_file
(
const
std
::
string
&
det_model_path
,
const
std
::
string
&
rec_model_path
);
/**
*
返回OCR结果
*
Return OCR result
* @param dims
* @param input_data
* @param input_len
...
...
@@ -69,7 +69,7 @@ public:
private:
/**
*
从第一个模型的结果中计算有文字的四边形
*
calcul Polygone from the result image of first model
* @param pred
* @param output_height
* @param output_width
...
...
@@ -81,7 +81,7 @@ private:
const
cv
::
Mat
&
origin
);
/**
*
第二个模型的推理
*
infer for second model
*
* @param boxes
* @param origin
...
...
@@ -91,14 +91,14 @@ private:
infer_rec
(
const
std
::
vector
<
std
::
vector
<
std
::
vector
<
int
>>>
&
boxes
,
const
cv
::
Mat
&
origin
);
/**
*
第二个模型提取文字的后处理
*
Postprocess or sencod model to extract text
* @param res
* @return
*/
std
::
vector
<
int
>
postprocess_rec_word_index
(
const
PredictorOutput
&
res
);
/**
*
计算第二个模型的文字的置信度
*
calculate confidence of second model text result
* @param res
* @return
*/
...
...
deploy/android_demo/app/src/main/cpp/ppredictor.h
浏览文件 @
ec903eb5
...
...
@@ -7,7 +7,7 @@
namespace
ppredictor
{
/**
* PaddleLite Preditor
通用接口
* PaddleLite Preditor
Common Interface
*/
class
PPredictor_Interface
{
public:
...
...
@@ -21,7 +21,7 @@ public:
};
/**
*
通用推理
*
Common Predictor
*/
class
PPredictor
:
public
PPredictor_Interface
{
public:
...
...
@@ -33,9 +33,9 @@ public:
}
/**
*
初始化paddlitelite的opt模型,nb格式,与init_paddle二选一
*
init paddlitelite opt model,nb format ,or use ini_paddle
* @param model_content
* @return 0
目前是固定值0, 之后其他值表示失败
* @return 0
*/
virtual
int
init_nb
(
const
std
::
string
&
model_content
);
...
...
deploy/android_demo/app/src/main/cpp/predictor_output.h
浏览文件 @
ec903eb5
...
...
@@ -21,10 +21,10 @@ public:
const
std
::
vector
<
std
::
vector
<
uint64_t
>>
get_lod
()
const
;
const
std
::
vector
<
int64_t
>
get_shape
()
const
;
std
::
vector
<
float
>
data
;
//
通常是float返回,与下面的data_int二选一
std
::
vector
<
int
>
data_int
;
//
少数层是int返回,与 data二选一
std
::
vector
<
int64_t
>
shape
;
// PaddleLite
输出层的
shape
std
::
vector
<
std
::
vector
<
uint64_t
>>
lod
;
// PaddleLite
输出层的
lod
std
::
vector
<
float
>
data
;
//
return float, or use data_int
std
::
vector
<
int
>
data_int
;
//
several layers return int ,or use data
std
::
vector
<
int64_t
>
shape
;
// PaddleLite
output
shape
std
::
vector
<
std
::
vector
<
uint64_t
>>
lod
;
// PaddleLite
output
lod
private:
std
::
unique_ptr
<
const
paddle
::
lite_api
::
Tensor
>
_tensor
;
...
...
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/AppCompatPreferenceActivity.java
浏览文件 @
ec903eb5
...
...
@@ -19,15 +19,16 @@ package com.baidu.paddle.lite.demo.ocr;
import
android.content.res.Configuration
;
import
android.os.Bundle
;
import
android.preference.PreferenceActivity
;
import
android.support.annotation.LayoutRes
;
import
android.support.annotation.Nullable
;
import
android.support.v7.app.ActionBar
;
import
android.support.v7.app.AppCompatDelegate
;
import
android.support.v7.widget.Toolbar
;
import
android.view.MenuInflater
;
import
android.view.View
;
import
android.view.ViewGroup
;
import
androidx.annotation.LayoutRes
;
import
androidx.annotation.Nullable
;
import
androidx.appcompat.app.ActionBar
;
import
androidx.appcompat.app.AppCompatDelegate
;
import
androidx.appcompat.widget.Toolbar
;
/**
* A {@link PreferenceActivity} which implements and proxies the necessary calls
* to be used with AppCompat.
...
...
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MainActivity.java
浏览文件 @
ec903eb5
...
...
@@ -19,11 +19,6 @@ import android.os.HandlerThread;
import
android.os.Message
;
import
android.preference.PreferenceManager
;
import
android.provider.MediaStore
;
import
android.support.annotation.NonNull
;
import
android.support.v4.app.ActivityCompat
;
import
android.support.v4.content.ContextCompat
;
import
android.support.v4.content.FileProvider
;
import
android.support.v7.app.AppCompatActivity
;
import
android.text.method.ScrollingMovementMethod
;
import
android.util.Log
;
import
android.view.Menu
;
...
...
@@ -33,6 +28,12 @@ import android.widget.ImageView;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
androidx.annotation.NonNull
;
import
androidx.appcompat.app.AppCompatActivity
;
import
androidx.core.app.ActivityCompat
;
import
androidx.core.content.ContextCompat
;
import
androidx.core.content.FileProvider
;
import
java.io.File
;
import
java.io.IOException
;
import
java.io.InputStream
;
...
...
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/MiniActivity.java
0 → 100644
浏览文件 @
ec903eb5
package
com.baidu.paddle.lite.demo.ocr
;
import
android.graphics.Bitmap
;
import
android.graphics.BitmapFactory
;
import
android.os.Build
;
import
android.os.Bundle
;
import
android.os.Handler
;
import
android.os.HandlerThread
;
import
android.os.Message
;
import
android.util.Log
;
import
android.view.View
;
import
android.widget.Button
;
import
android.widget.ImageView
;
import
android.widget.TextView
;
import
android.widget.Toast
;
import
androidx.appcompat.app.AppCompatActivity
;
import
java.io.IOException
;
import
java.io.InputStream
;
public
class
MiniActivity
extends
AppCompatActivity
{
public
static
final
int
REQUEST_LOAD_MODEL
=
0
;
public
static
final
int
REQUEST_RUN_MODEL
=
1
;
public
static
final
int
REQUEST_UNLOAD_MODEL
=
2
;
public
static
final
int
RESPONSE_LOAD_MODEL_SUCCESSED
=
0
;
public
static
final
int
RESPONSE_LOAD_MODEL_FAILED
=
1
;
public
static
final
int
RESPONSE_RUN_MODEL_SUCCESSED
=
2
;
public
static
final
int
RESPONSE_RUN_MODEL_FAILED
=
3
;
private
static
final
String
TAG
=
"MiniActivity"
;
protected
Handler
receiver
=
null
;
// Receive messages from worker thread
protected
Handler
sender
=
null
;
// Send command to worker thread
protected
HandlerThread
worker
=
null
;
// Worker thread to load&run model
protected
volatile
Predictor
predictor
=
null
;
private
String
assetModelDirPath
=
"models/ocr_v1_for_cpu"
;
private
String
assetlabelFilePath
=
"labels/ppocr_keys_v1.txt"
;
private
Button
button
;
private
ImageView
imageView
;
// image result
private
TextView
textView
;
// text result
@Override
protected
void
onCreate
(
Bundle
savedInstanceState
)
{
super
.
onCreate
(
savedInstanceState
);
setContentView
(
R
.
layout
.
activity_mini
);
Log
.
i
(
TAG
,
"SHOW in Logcat"
);
// Prepare the worker thread for mode loading and inference
worker
=
new
HandlerThread
(
"Predictor Worker"
);
worker
.
start
();
sender
=
new
Handler
(
worker
.
getLooper
())
{
public
void
handleMessage
(
Message
msg
)
{
switch
(
msg
.
what
)
{
case
REQUEST_LOAD_MODEL:
// Load model and reload test image
if
(!
onLoadModel
())
{
runOnUiThread
(
new
Runnable
()
{
@Override
public
void
run
()
{
Toast
.
makeText
(
MiniActivity
.
this
,
"Load model failed!"
,
Toast
.
LENGTH_SHORT
).
show
();
}
});
}
break
;
case
REQUEST_RUN_MODEL:
// Run model if model is loaded
final
boolean
isSuccessed
=
onRunModel
();
runOnUiThread
(
new
Runnable
()
{
@Override
public
void
run
()
{
if
(
isSuccessed
){
onRunModelSuccessed
();
}
else
{
Toast
.
makeText
(
MiniActivity
.
this
,
"Run model failed!"
,
Toast
.
LENGTH_SHORT
).
show
();
}
}
});
break
;
}
}
};
sender
.
sendEmptyMessage
(
REQUEST_LOAD_MODEL
);
// corresponding to REQUEST_LOAD_MODEL, to call onLoadModel()
imageView
=
findViewById
(
R
.
id
.
imageView
);
textView
=
findViewById
(
R
.
id
.
sample_text
);
button
=
findViewById
(
R
.
id
.
button
);
button
.
setOnClickListener
(
new
View
.
OnClickListener
()
{
@Override
public
void
onClick
(
View
v
)
{
sender
.
sendEmptyMessage
(
REQUEST_RUN_MODEL
);
}
});
}
@Override
protected
void
onDestroy
()
{
onUnloadModel
();
if
(
Build
.
VERSION
.
SDK_INT
>=
Build
.
VERSION_CODES
.
JELLY_BEAN_MR2
)
{
worker
.
quitSafely
();
}
else
{
worker
.
quit
();
}
super
.
onDestroy
();
}
/**
* call in onCreate, model init
*
* @return
*/
private
boolean
onLoadModel
()
{
if
(
predictor
==
null
)
{
predictor
=
new
Predictor
();
}
return
predictor
.
init
(
this
,
assetModelDirPath
,
assetlabelFilePath
);
}
/**
* init engine
* call in onCreate
*
* @return
*/
private
boolean
onRunModel
()
{
try
{
String
assetImagePath
=
"images/5.jpg"
;
InputStream
imageStream
=
getAssets
().
open
(
assetImagePath
);
Bitmap
image
=
BitmapFactory
.
decodeStream
(
imageStream
);
// Input is Bitmap
predictor
.
setInputImage
(
image
);
return
predictor
.
isLoaded
()
&&
predictor
.
runModel
();
}
catch
(
IOException
e
)
{
e
.
printStackTrace
();
return
false
;
}
}
private
void
onRunModelSuccessed
()
{
Log
.
i
(
TAG
,
"onRunModelSuccessed"
);
textView
.
setText
(
predictor
.
outputResult
);
imageView
.
setImageBitmap
(
predictor
.
outputImage
);
}
private
void
onUnloadModel
()
{
if
(
predictor
!=
null
)
{
predictor
.
releaseModel
();
}
}
}
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/Predictor.java
浏览文件 @
ec903eb5
...
...
@@ -38,7 +38,7 @@ public class Predictor {
protected
float
scoreThreshold
=
0.1f
;
protected
Bitmap
inputImage
=
null
;
protected
Bitmap
outputImage
=
null
;
protected
String
outputResult
=
""
;
protected
volatile
String
outputResult
=
""
;
protected
float
preprocessTime
=
0
;
protected
float
postprocessTime
=
0
;
...
...
@@ -46,6 +46,16 @@ public class Predictor {
public
Predictor
()
{
}
public
boolean
init
(
Context
appCtx
,
String
modelPath
,
String
labelPath
)
{
isLoaded
=
loadModel
(
appCtx
,
modelPath
,
cpuThreadNum
,
cpuPowerMode
);
if
(!
isLoaded
)
{
return
false
;
}
isLoaded
=
loadLabel
(
appCtx
,
labelPath
);
return
isLoaded
;
}
public
boolean
init
(
Context
appCtx
,
String
modelPath
,
String
labelPath
,
int
cpuThreadNum
,
String
cpuPowerMode
,
String
inputColorFormat
,
long
[]
inputShape
,
float
[]
inputMean
,
...
...
@@ -76,11 +86,7 @@ public class Predictor {
Log
.
e
(
TAG
,
"Only BGR color format is supported."
);
return
false
;
}
isLoaded
=
loadModel
(
appCtx
,
modelPath
,
cpuThreadNum
,
cpuPowerMode
);
if
(!
isLoaded
)
{
return
false
;
}
isLoaded
=
loadLabel
(
appCtx
,
labelPath
);
boolean
isLoaded
=
init
(
appCtx
,
modelPath
,
labelPath
);
if
(!
isLoaded
)
{
return
false
;
}
...
...
@@ -222,7 +228,7 @@ public class Predictor {
for
(
int
i
=
0
;
i
<
warmupIterNum
;
i
++)
{
paddlePredictor
.
runImage
(
inputData
,
width
,
height
,
channels
,
inputImage
);
}
warmupIterNum
=
0
;
//
之后不要再warm了
warmupIterNum
=
0
;
//
do not need warm
// Run inference
start
=
new
Date
();
ArrayList
<
OcrResultModel
>
results
=
paddlePredictor
.
runImage
(
inputData
,
width
,
height
,
channels
,
inputImage
);
...
...
@@ -317,7 +323,7 @@ public class Predictor {
for
(
Point
p
:
result
.
getPoints
())
{
sb
.
append
(
"("
).
append
(
p
.
x
).
append
(
","
).
append
(
p
.
y
).
append
(
") "
);
}
Log
.
i
(
TAG
,
sb
.
toString
());
Log
.
i
(
TAG
,
sb
.
toString
());
// show LOG in Logcat panel
outputResultSb
.
append
(
i
+
1
).
append
(
": "
).
append
(
result
.
getLabel
()).
append
(
"\n"
);
}
outputResult
=
outputResultSb
.
toString
();
...
...
deploy/android_demo/app/src/main/java/com/baidu/paddle/lite/demo/ocr/SettingsActivity.java
浏览文件 @
ec903eb5
...
...
@@ -5,7 +5,8 @@ import android.os.Bundle;
import
android.preference.CheckBoxPreference
;
import
android.preference.EditTextPreference
;
import
android.preference.ListPreference
;
import
android.support.v7.app.ActionBar
;
import
androidx.appcompat.app.ActionBar
;
import
java.util.ArrayList
;
import
java.util.List
;
...
...
deploy/android_demo/app/src/main/res/layout/activity_main.xml
浏览文件 @
ec903eb5
<?xml version="1.0" encoding="utf-8"?>
<android
.support.constrain
t.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
<android
x.constraintlayout.widge
t.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
...
...
@@ -96,4 +96,4 @@
</RelativeLayout>
</android.support.constraint.ConstraintLayout>
\ No newline at end of file
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
deploy/android_demo/app/src/main/res/layout/activity_mini.xml
0 → 100644
浏览文件 @
ec903eb5
<?xml version="1.0" encoding="utf-8"?>
<!-- for MiniActivity Use Only -->
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android=
"http://schemas.android.com/apk/res/android"
xmlns:app=
"http://schemas.android.com/apk/res-auto"
xmlns:tools=
"http://schemas.android.com/tools"
android:layout_width=
"match_parent"
android:layout_height=
"match_parent"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintLeft_toRightOf=
"parent"
tools:context=
".MainActivity"
>
<TextView
android:id=
"@+id/sample_text"
android:layout_width=
"0dp"
android:layout_height=
"wrap_content"
android:text=
"Hello World!"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toBottomOf=
"@id/imageView"
android:scrollbars=
"vertical"
/>
<ImageView
android:id=
"@+id/imageView"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:paddingTop=
"20dp"
android:paddingBottom=
"20dp"
app:layout_constraintBottom_toTopOf=
"@id/imageView"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
app:layout_constraintTop_toTopOf=
"parent"
tools:srcCompat=
"@tools:sample/avatars"
/>
<Button
android:id=
"@+id/button"
android:layout_width=
"wrap_content"
android:layout_height=
"wrap_content"
android:layout_marginBottom=
"4dp"
android:text=
"Button"
app:layout_constraintBottom_toBottomOf=
"parent"
app:layout_constraintLeft_toLeftOf=
"parent"
app:layout_constraintRight_toRightOf=
"parent"
tools:layout_editor_absoluteX=
"161dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
\ No newline at end of file
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录