안녕하세요~ 챠니입니다! :)
오늘은 사인패드, 시그니처패드 (Signaturepad)에 대해서 알아보겠습니다.
해당 기능은 네이티브의 기본으로 내장되어 있는 기능은 아니고, 똑똑한 사람이 Github에 자신이 작업한 내용을 올린것을 활용하여 구현하는 방법입니다 :)
Signaturepad
먼저 오늘 기능을 먼저 구현하여 공유를 하고 있는 사람의 GitHub의 주소는 다음과 같습니다.
보다더 자세히 알아보고 싶은 분은 아래의 링크의 Readme를 읽어 보시길 바랍니다.
https://github.com/zahid-ali-shah/SignatureView
구현방법
1. build.gradle(:app) 에 dependencies를 추가합니다.
implementation 'com.kyanogen.signatureview:signature-view:1.2'
사인패드 기능을 지원하는 아래 2개가 더 있지만, 제가 사용하려고하니 잘 안되더라구요... 그래서 사용하지 못했습니다 :)
'com.github.gcacace:signature-pad:1.3.1'
'com.github.nsmarinro.SignatureView:librarySignature:0.1.2'
2. layout파일에 사인패드를 추가합니다.
<com.kyanogen.signatureview.SignatureView
xmlns:sign="http://schemas.android.com/apk/res-auto"
android:id="@+id/signature_pad"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:penColor="@android:color/black"
sign:enableSignature="true" />
여기까지 따라 오셨다면 가장 기초적인 사인패드 기능을 구현 할 수 있습니다.
하지만 사인패드를 구현하는것에서 끝나는 것이 아니라, 사인패드에 그린 후 지워주는 Clear기능과 Save저장기능 까지 구현을 해보겠습니다.
---------------------------------------------------------------------------------------------------------------------
여기서부터는 전체 코드를 보여드리겠습니다.
사인패드를 구현하는 부분은 쉽지만 지우기 및 갤러리 저장 기능이 kt파일의 대부분이라고 생각하시면 되겠습니다.
[MainActivity.kt]
/** MainActivity.kt*/
class MainActivity : AppCompatActivity() {
lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
//화면모드 설정 (세로-SCREEN_ORIENTATION_PORTRAIT, 가로-SCREEN_ORIENTATION_LANDSCAPE)
requestedOrientation = ActivityInfo.SCREEN_ORIENTATION_PORTRAIT
initSignaturePad()
}
private fun initSignaturePad(){
/** 초기화 */
binding.bClear.setOnClickListener {
binding.signaturePad.clearCanvas()
}
/** 저장 */
binding.bSave.setOnClickListener {
if(!binding.signaturePad.isBitmapEmpty){
/** 권한 체크 */
if(!checkPermission(Manifest.permission.READ_EXTERNAL_STORAGE) || !checkPermission(Manifest.permission.WRITE_EXTERNAL_STORAGE)) {
return@setOnClickListener
}
/** 그림 저장 */
if(!imageExternalSave(binding.signaturePad.signatureBitmap, this.getString(R.string.app_name))){
Toast.makeText(this, "사인패드 저장에 실패하였습니다", Toast.LENGTH_SHORT).show()
}else{
Toast.makeText(this, "사인패드를 갤러리에 저장하였습니다.", Toast.LENGTH_SHORT).show()
}
}else {
Toast.makeText(this, "사인패드가 비어있습니다.", Toast.LENGTH_SHORT).show()
}
}
}
/** 이미지 저장 */
private fun imageExternalSave(bitmap: Bitmap, path: String): Boolean {
val state = Environment.getExternalStorageState()
if (Environment.MEDIA_MOUNTED == state) {
val rootPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_PICTURES).toString()
val dirName = "/" + path
val fileName = System.currentTimeMillis().toString() + ".png"
val savePath = File(rootPath + dirName)
savePath.mkdirs()
val file = File(savePath, fileName)
if (file.exists()) file.delete()
try {
val out = FileOutputStream(file)
bitmap.compress(Bitmap.CompressFormat.PNG, 100, out)
out.flush()
out.close()
//갤러리 갱신
galleyAddPic(file)
return true
} catch (e: Exception) {
e.printStackTrace()
}
}
return false
}
/** 갤러리 갱신 */
private fun galleyAddPic(file: File){
Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE).also { mediaScanIntent ->
mediaScanIntent.data = Uri.fromFile(file)
sendBroadcast(mediaScanIntent)
}
}
/** 권한 체크 */
private fun checkPermission(permission: String): Boolean {
val permissionChecker = ContextCompat.checkSelfPermission(applicationContext, permission)
//권한이 없으면 권한 요청
if (permissionChecker == PackageManager.PERMISSION_GRANTED){
return true
}
ActivityCompat.requestPermissions(this, arrayOf(permission), 100)
return false
}
}
[activity_main.xml]
<?xml version="1.0" encoding="utf-8"?>
<!-- activity_main.xml-->
<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"
android:background="#000000"
tools:context=".MainActivity">
<com.kyanogen.signatureview.SignatureView
xmlns:sign="http://schemas.android.com/apk/res-auto"
android:id="@+id/signature_pad"
android:layout_width="match_parent"
android:layout_height="0dp"
android:background="#FFFFFF"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:penColor="@android:color/black"
sign:enableSignature="true" />
<Button
android:id="@+id/b_clear"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#333333"
android:enabled="true"
android:gravity="center"
android:padding="20dp"
android:text="Clear"
android:textColor="#FFFFFF"
app:layout_constraintEnd_toStartOf="@+id/b_save"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/signature_pad" />
<Button
android:id="@+id/b_save"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#333333"
android:enabled="true"
android:gravity="center"
android:padding="20dp"
android:text="Save"
android:textColor="#FFFFFF"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/b_clear"
app:layout_constraintTop_toBottomOf="@+id/signature_pad" />
</androidx.constraintlayout.widget.ConstraintLayout>
완성된 앱 모습
CLEAR, SAVE버튼 eventListener를 통해서 사인패드 클리어 및 갤러리 저장기능을 구현하였습니다.
여기가지 사인패드에 대해서 알아보았습니다.
소스코드
[소스코드]
싸인패드, 시그니처패드(SignaturePad):
https://github.com/younminchan/kotlin-study/tree/main/Signaturepad_kotlin
질문 또는 궁굼한 부분은 댓글을 남겨주세요! 친절하게 답변드리겠습니다!
응원의 댓글은 저에게 큰 힘이 된답니다! :)
즐거운 하루되세요!
깃허브 보러 놀러오세요 👇 (맞팔환영)
https://github.com/younminchan
'🖥 Programming > 📱 Android (Kotlin)' 카테고리의 다른 글
[Android][Kotlin] 페이스북 로그인 API 연동(Facebook Login) (0) | 2022.04.29 |
---|---|
[Android][kotlin] TaskStackBuilder getPendingIntent 최신 intent만 작동하는 버그 해결방법 (0) | 2022.04.27 |
[Android][kotlin] 빌드 변형 구성 (ProductFlavors) 한 개의 프로젝트로 여러개의 앱 만들기 (0) | 2022.04.21 |
[Android][kotlin] StatusBar 상태바 색상 변경, 상태바 아이콘 색상 변경 방법 (title StatusBar 색상 변경) (0) | 2022.04.18 |
[Android] 코드 전체검색 및 코드 전체 변경 (0) | 2022.04.14 |
[Android] Execution failed for task ':app:signReleaseBundle'. / Cannot recover key 오류 및 해결방법 (0) | 2022.04.07 |
[Android] Execution failed for task ':app:processDebugGoogleServices'. 오류 해 (0) | 2022.03.31 |
[Android][kotlin] 진동 울리기 (0) | 2022.03.29 |