Notice
Recent Posts
Recent Comments
Link
«   2025/04   »
1 2 3 4 5
6 7 8 9 10 11 12
13 14 15 16 17 18 19
20 21 22 23 24 25 26
27 28 29 30
Archives
Today
Total
관리 메뉴

gogumaC

StickerView | 화면에 스티커 추가,편집하기 [Kotlin] 본문

Android/도움되는 오픈소스

StickerView | 화면에 스티커 추가,편집하기 [Kotlin]

gogumaC 2021. 6. 7. 11:51

블로그에 쓸 주제는 지금하고있는 프로젝트에서 사용한걸 다시 정리하는 목적으로 결정한다.

원래 이 카테고리에 쓸 주제가 Image Cropper와 StickerView였는데 Image Cropper는 다른 분들께서 사용법을 종종 올려놓으신 반면 StickerView는 사용법이 없어서 애를 먹었기때문에 StickerView를 먼저 포스팅 해보고자한다!

일단 나는 앱개발을 배워가고 있는 입장이라 아직 잘 모르는 부분들도 많아서 틀린부분이 있을수 있으니 이 포스팅을 전적으로 의지하지 않으셨으면 좋겠다!

 

StickerView

https://github.com/wuapnjie/StickerView

 

wuapnjie/StickerView

[No more support] A view which can add sticker and zoom,drag,delete it - wuapnjie/StickerView

github.com

일단 이 소스가 무엇을 위한것인지 말해보자면 다들 짐작하셨다시피 화면에 스티커를 추가하고 편집하는데 사용하는 소스이다.

스티커를 추가,삭제할 수 있고 돌리기,크기변경,뒤집기, 위치변경 등등 스티커 관련 기능이 구현되어있다!


사용법

위 깃주소에 들어가보면 README에 개발자분이 소스코드를 복사해서 커스텀하는방식으로 이용하라고 맨 위에 적혀있다.

보통 오픈소스 라이브러리를 쓸때 dependencies에 코드를 추가하는 방법과는 달라서 이런 방법으로 오픈소스를 제공할수도 있구나 하는걸 새로 배웠다. (개인적인 추측이지만 dependencies에쓰면 코드 커스텀이 불가능해서 그런거아닐까?)

사용법을 요약하면 아래와같다.

1. 소스파일 복사
2. 파일 수정
3. 레이아웃파일에 추가
4. 소스코드 작업

이제 각 단계별로 상세하게 설명을 하도록 하겠다.

 

1. 소스코드 복사

깃 페이지 상단에 보면 위와같은 화면이 보인다.

여기서 Code버튼을 눌러 DownloadZIP으로 프로젝트코드 전체를 압축파일로 받는다.

 

그럼 이런식으로 파일이 생길텐데 이건 개발자분이 만드신 예제 프로젝트이므로 이 안에서 필요한 부분만 골라서 자신의 프로젝트에 붙여넣기 하면 된다!

일단 우리가 써야하는 파일은 모두 StickerView-master/sticker/src/main폴더에 있으므로 그쪽으로 이동한다.

여기에서 java폴더를 계속 타고 들어가서 sticker폴더에있는 모든 소스파일을 가져와야한다.(나는 그냥 sticker폴더를 복사해서 붙여넣었다.)

다음으로는 res폴더에서 drawable 이 붙은 파일들은 res폴더에 붙여넣기해주고, value폴더안의 attrs.xml 파일을 res/value폴더안에 넣어준다.

attrs파일이 원래 있는사람은 코드가 길지 않으니 파일을 열어서 필요한 부분을 복붙해주거나 덮어쓰기 해주면된다.

sticker폴더의 경우 스티커기능에 대한 로직을 담고있는 파일들이고 res폴더는 스티커 편집에 사용되는 아이콘같은 이미지 자료와 커스텀뷰에 대한 속성들이 있는 폴더이다.

정리해보면

요 파일들을 카피해서 가져오면 된다!

각 파일들 역할 대한 설명을 달고싶은데 필요할때마다 달아보고 나중에 시간이 되면 요약해서 올려두도록하겠다

최종적으로 안드로이드 스튜디오에 다음과 같이 붙여넣기가 됬다면 붙여넣기는 끝난것이다!

 

2. 파일 수정

스티커뷰를 xml에 추가해서 사용하려고할때 스티커뷰를 palette에서 찾을수 없을것이다. 빌드를 하면 이 문제는 해결된다.

그런데 상단에 망치버튼을 눌러서 빌드해보면

이런식으로 오류가 뜨게 된다. 이건 내생각으로는 소스의 마지막 업데이트가 2017년이어서 androidx에 대한 반영이 없는것같다.ㅜㅜ

아마 붙여넣기 한 몇몇 소스파일이 저렇게 되어있을텐데 오류가 생긴 줄을 다음과같이 바꿔주면된다.

import android.support.annotation.@@@; -> import androidx.annotation.@@@

import android.support.v4.@@@; -> 삭제하고 빨간줄뜨는 코드부분은 ctrl+alt눌러서 자동 import시켜주자

모든 오류를 수정하고 빌드하면

이렇게 Project카테고리에 StickerView가 생긴것을 확인할수 있다!

3. 레이아웃 파일에 추가

이제 xml에 배치해보자!

<?xml version="1.0" encoding="utf-8"?>
<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"
    tools:context=".MainActivity">

    <isbean.android_practice.android_test.StickerView
        android:id="@+id/stickerView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:showBorder="true"
        app:showIcons="true" />

    <Button
        android:id="@+id/btnAddSticker"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginBottom="20dp"
        android:text="스티커 추가"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.498"
        app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>

요렇게 화면을 스티커뷰로 꽉채우고 스티커추가를 위해 버튼하나를 만들었다.

 

**

스티커뷰는 스티커가 아니다! 스티커를 생성하고 배치할수있는 공간이라고 생각하면 된다!

스티커는 Sticker로 따로 정의해서 사용한다.

(나는 스티커뷰가 스티커인줄알아서 이해하기 힘들었다ㅠㅠ)

 

스티커뷰는 일종의 커스텀뷰이므로 attrs.xml파일을 보면 스티커뷰에서 사용할수있는 커스텀 속성들을 확인할수있다.

속성명 타입 설명
showIcons boolean 스티커를 선택했을때 삭제,크기변경,뒤집기 등 아이콘을 나타낼것인지
showBorder boolean 스티커를 선택했을때 해당스티커의 테두리를 나타낼것인지
bringToFrontCurrentSticker boolean (이건사실 안써봤는데 추측으로는) 최근 스티커를 가장 앞으로 배치할것인지
borderColor color 테두리 색깔지정
bolderAlpha integer 테두리 투명도 지정

필요한 속성이 있으면 추가해보자.

이것들 외에도 스티커뷰는 '프레임레이아웃'을 상속받아 만들었으므로 프레임레이아웃의 속성은 모두 이용할수있다!

 

4. 소스코드 작업

이렇게 레이아웃에 배치가 끝나면 이제 소스코드(MainActivity.kt)로 넘어가서 스티커에 관한 로직을 설정해야한다.

이부분은 README에 있는데 처음봤을때는 이게 뭘까 싶었다. 좀 알고보니까 지금은 친절한 설명인것같다.

일단 스티커뷰와 버튼의 뷰 객체를 선언해주자

class MainActivity : AppCompatActivity() {
    private lateinit var stickerView:StickerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        stickerView=findViewById<StickerView>(R.id.stickerView)
        val btnAddSticker=findViewById<Button>(R.id.btnAddSticker)

다른 코드를 작성하기에 앞서서 만약 편집아이콘을 사용할거면 아이콘을 정의하고 기능을 설정하고 스티커뷰에 연결하는 과정이 필요하다.

일단 아이콘 객체들을 생성하자

//BitmapStickerIcon(아이콘이미지 drawable,아이콘 위치)
//아이콘위치중에 RIGHT_BOTOM은 만드신분이 오타를 수정안하신듯하다!
        val deleteIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_close_white_18dp)
            ,BitmapStickerIcon.LEFT_TOP)
        val flipIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_flip_white_18dp)
            ,BitmapStickerIcon.RIGHT_BOTOM)
        val scaleIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_scale_white_18dp)
            ,BitmapStickerIcon.LEFT_BOTTOM)

이제 내가 어떤 아이콘을 사용할건지는 썼으니 각 아이콘에 기능을 주어야한다.

이 부분은 setIconEvent(StickerIconEvent)를 사용한다.

deleteIcon.setIconEvent(DeleteIconEvent())
//이렇게도 할수있다!
flipIcon.iconEvent=FlipHorizontallyEvent()
scaleIcon.setIconEvent(ZoomIconEvent())

setIconEvent의 매개변수로는 StickerIconEvent인터페이스를 상속받아 만들어진 객체들을 사용한다.

우리가 붙여넣기한 파일에서 끝이 Event로 끝나는 파일들이 그거다!

flip같은 경우는 세 종류가 있는데 가로뒤집기(FlipHorizontallyEvent()),세로뒤집기(FlipVerticallyEvent),대각선뒤집기(FlipBothDirectionEvent())이다. 여기서 필요한 기능으로 선택해서 넣길바란다.

나는 좌우 뒤집기가 좋을것같아서 FlipHorizontallyEvent()를 넣어줬다.

이제 어떤 아이콘을 쓸거고 어떤 기능을 쓸건지 결정했으니 우리가 레이아웃에 넣은 스티커뷰에 아이콘을 연결해주어야한다.

//만든 아이콘을 리스트로 만들어주기
val iconList=listOf(deleteIcon,flipIcon,scaleIcon)

//setIcons((Mutalbe)List<BitmapStickerIcon>)
stickerView.setIcons(iconList)

스티커뷰에 연결할때 매개변수타입이 리스트이기때문에 위에서 미리 위에서 정의한 아이콘들을 리스트로 만들어 주었다.

여기까지 하면 아이콘에 대한것은 마무리가 되었다.

우리는 스티커를 추가하기 위해서 이 소스를 사용하는것이므로 이제 스티커를 추가해야한다. StickerView의 스티커와 관련된 기본적인 메서드들은 다음과 같다.

사실 나도 다 써본건 아니라서 몇몇 기능은 이름을 보고 추측해보았다. 근 시일내에 확인해봐야겠다. 앞으로 (추측)이라고 써진 부분들은 아직 확인이 덜된부분이라고 생각하면 될것같다.

메서드 설명
addSticker(sticker) sticker을 추가
replace(sticker) (추측)sticker을 변경
remove(sticker) sticker을 제거
removeCurrentSticker() 가장 나중에 추가한 스티커 제거
removeAllStickers() 모든 스티커 제거
setLocked(boolean) (추측)스티커 위치고정

이 외에도 다른 메서드가 많은데 그건 나중에 다뤄보도록하겠다. 잘찾아보면 다른 쓸만한 기능도 있고 만든지 오래되서 지금은 약간 수정이 필요한 기능들도 있다.

이제 위내용을 이용해서 버튼을 누르면 스티커를 추가할수있게 해보겠다.

저 위의 메서드를 바로 이용할수있으면 참 좋겠지만 매개변수가 Sticker여야 하기 때문에 우리가 넣고싶은 이미지를 Sticker타입으로 변환해주는 과정이 필요하다.

깃에 올라와있는 예제 코드는 다음과 같다. onCreate()바깥에 추가해주면된다.

loadSticker()에서 stickerView를 쓰기 위해 처음에 stickerView만 전역변수로 선언해 주었다.

fun loadSticker(){
            val drawable=ContextCompat.getDrawable(this,R.drawable.sticker_sample)
            val drawableSticker=DrawableSticker(drawable)
            stickerView.addSticker(drawableSticker)
        }

이제 버튼이 눌리면 loadSticker를 호출하도록 코드를 작성한다.

btnAddSticker.setOnClickListener {
     loadSticker()
}

위 코드를 모두 합친 전체 코드는 다음과 같다.

package isbean.android_practice.android_test

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.Button
import androidx.core.content.ContextCompat

class MainActivity : AppCompatActivity() {
    private lateinit var stickerView:StickerView

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        stickerView=findViewById<StickerView>(R.id.stickerView)
        val btnAddSticker=findViewById<Button>(R.id.btnAddSticker)

        //아이콘 설정
        val deleteIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_close_white_18dp)
            ,BitmapStickerIcon.LEFT_TOP)
        val flipIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_flip_white_18dp)
            ,BitmapStickerIcon.RIGHT_BOTOM)
        val scaleIcon=BitmapStickerIcon(ContextCompat.getDrawable(this,R.drawable.sticker_ic_scale_white_18dp)
            ,BitmapStickerIcon.LEFT_BOTTOM)

        val iconList=listOf(deleteIcon,flipIcon,scaleIcon)

        //아이콘에 이벤트 할당
        deleteIcon.setIconEvent(DeleteIconEvent())
        flipIcon.iconEvent=FlipHorizontallyEvent()
        scaleIcon.setIconEvent(ZoomIconEvent())

        //스티커뷰에 아이콘연결
        stickerView.setIcons(iconList)


        //버튼 눌리면 스티커추가
        btnAddSticker.setOnClickListener {
            loadSticker()
        }


    }

    fun loadSticker(){
        val drawable=ContextCompat.getDrawable(this,R.drawable.sticker_sample)
        val drawableSticker=DrawableSticker(drawable)
        stickerView.addSticker(drawableSticker)
    }


}

이제 실행시켜주면 요렇게 스티커를 추가할수있다!!

 

짜잔 이걸로 화면에 스티커 추가하기가 끝났다!

오늘은 이걸로 끝이다. 사실 다른것도 오늘 다쓰려고 했는데 이거쓰는데 3시간정도걸렸다😂😂

일기처럼 쓰는 글이아닌 블로그글은 이게 처음이라 잘 읽힐지는 모르겠지만 쓰고나니까 좀 뿌듯하다.

다음에는 오늘 설명못했던 스티커뷰의 다른 기능들로 스티커뷰 심화를 포스팅해야 할 것 같다.

+) 까먹고 안적었는데 프래그먼트에서 사용할때는 context 부분을 this.requireContext()로 바꿔주면된다

loadSticker는 아마 내 기억으로는 context를 매개변수로 줬던것같다

PS.

누가 볼지는 모르겠지만 공부하고 정리하려고 쓴 글이므로 틀린부분이나 이해가어려운부분은 언제든지 알려주시면 감사하겠습니다!

호옥시 궁금한점이 있으면 제가 아는 부분에 한해서는 최대한 열심히 답글을 달아드리도록 노력해보겠습니다😊