val animation: ObjectAnimator = ObjectAnimator.ofFloat(this, "rotation", degree)
    animation.apply {
    duration = getRollDuration()
    interpolator = DecelerateInterpolator()
    addListener(object: Animator.AnimatorListener {
        override fun onAnimationStart(p0: Animator?) {
        }

        override fun onAnimationEnd(p0: Animator?) {
            var degree = rotation%360
            var sweep = 360 / PAINTS.size
            var position = PAINTS.size-1 - (degree/sweep).toInt();
            listener?.onRouletteStop(position)
        }

        override fun onAnimationCancel(p0: Animator?) {
        }

        override fun onAnimationRepeat(p0: Animator?) {
        }
    })
}
animation.start()

코드는 네 줄인데 이틀이나 잡아먹었다.

돌아간만큼 - 된다고 생각하고 해당하는 각도의 위치를 계산하였더니 된다.

 


 

다 써놓고 하는 말이지만 이거를 포스팅으로 써도 될지 확신이 들지 않았다.

하루 삽질하고 오늘 퇴근하면서 주차장에서 번쩍 생각이 들어서 해봤더니.. 어라 되네??

그래서 내가 이해하고 만든 게 아닌...? 근데 결과는 잘 나오는...? 그런 코드라..

그냥 '어 이러면 될 거 같은데?' 했더니 되버린.. 그런 코드다 ㅜㅜ

(하루아침에 이랬나 코딩&디버깅의 대부분이 '엥 혹시?ㅋㅋ'로 때려맞추는 나란 여자..)

 

 

 

어제 만든 액티비티에 돌리기 버튼과 원판을 추가하였다.

원판은 View를 상속받은 Custom View를 만들었고

돌리기 버튼을 누르면 원판이 돌아가도록 하였다.

 

원판의 영역 갯수는 일단 고정적으로 3개만 주었고

돌릴 때의 시간이나 돌리는 각도는 랜덤으로 주었다.

 

1. 원판 만들기

RouletteView.kt

class RouletteView : View {
    val COLORS = arrayOf(0xFFDDDDDD, 0xFFEEEEEE, 0xFFCCCCCC)	//룰렛 구역에 들어갈 색상
    val PAINTS = arrayOf(Paint(), Paint(), Paint())	//paint 객체를 미리 만들어두었다
    var rectF: RectF? = null	//원호를 그릴 때 쓰이는 RectF 객체를 미리 만들어두었다

    //... 생성자
    
    init {
        for (i in PAINTS.indices) {
            PAINTS[i].color = COLORS[i].toInt()	//각 페인트는 구역 색상대로 칠해지도록 설정
        }
    }

    override fun onDraw(canvas: Canvas?) {
        super.onDraw(canvas)

        canvas?.let {
            if (rectF == null) {
                rectF = RectF(0f, 0f, width.toFloat(), height.toFloat())	//캔버스를 꽉 채우는 rectF 정의
            }
            for (i in PAINTS.indices) {
                val sweepAngle = 360f / PAINTS.size	//한번에 회전시킬 각도 = 한바퀴/갯수
                val start = -90f + (i * sweepAngle)	//12시 각도에서 시작하기 위해 -90에 돌릴 각도를 추가하였다
                it.drawArc(rectF!!, start, sweepAngle, true, PAINTS[i])	//캔버스에 원호를 그림
            }
        }
    }

 

별 것 없다 (....)

 

 

2. 원판 돌리기

다음으로 뷰를 돌려줄 roll 함수를 추가해주었다.

public fun roll() {
    roll((Math.random() * 2000+900).toFloat())
}

public fun roll(degree: Float) {
    rotation = 0f
        
    val animation: ObjectAnimator = ObjectAnimator.ofFloat(this, "rotation", degree)
    animation.duration = getRollDuration()
    animation.interpolator = DecelerateInterpolator()
    animation.start()
}

 

마찬가지로 별 것 없다 (.....)

 

 

이제 마지막으로 액티비티의 버튼을 눌렀을 때 처리를 해 준다.

 

MainActivity.kt

val rouletteView = findViewById<RouletteView>(R.id.roulette)	//나는 레이아웃 뷰에서 룰렛 뷰를 추가해 뒀음.
findViewById<View>(R.id.btn_start).setOnClickListener {
    rouletteView.roll()	//룰렛을 돌린다
}

 

요렇게 하면 버튼을 누르면 원판이 돌아간다.

 

빙글빙글..

 

 

3. 원판 멈출 때 이벤트 처리

원판을 돌리는 것까진 했고, 원판이 멈췄을 때 어떤 액션을 취해주기 위해

OnRouletteListener 인터페이스를 만들고 추가해주었다.

 

OnRouletteListener.kt

interface OnRouletteListener {
    fun onRouletteStop(position: Int) : Unit
}

 

RouletteView에 전역변수로 OnRouletteListener 객체를 선언하고

roll에 animationListener를 달아주고, 끝날 때 listener를 실행하도록 하였다.

 

RoulletView.kt의 roll(degree: Float) 메소드 내부

animation.addListener(object: Animator.AnimatorListener {
    override fun onAnimationStart(p0: Animator?) {
        TODO("Not yet implemented")
    }

    override fun onAnimationEnd(p0: Animator?) {
        Log.i("TEST", "degree : $rotationX / $rotationY / $rotation");
        listener?.onRouletteStop(0)
    }

    override fun onAnimationCancel(p0: Animator?) {
        TODO("Not yet implemented")
    }

    override fun onAnimationRepeat(p0: Animator?) {
        TODO("Not yet implemented")
    }
})

 

그리고 MainActivity에서 listener를 정의해주었다.

 

MainActivity.kt

rouletteView.listener = object: OnRouletteListener {
    override fun onRouletteStop(position: Int) {
        Toast.makeText(this@MainActivity, "roullet stop", Toast.LENGTH_SHORT).show()
    }
}

 

코틀린 공부를 할 겸 서버가 필요없는 단순한 앱을 만들어보기로 했다.

네이버에 검색하면 나오는 원판돌리기를 만들 것이다 ^▽^

오늘은 일단 시작으로 시안을 만들고 앱바를 구현하는 것까지 하였다.

 

앱바 공식문서 : 

https://developer.android.com/guide/fragments/appbar

 

AppBar 사용  |  Android 개발자  |  Android Developers

AppBar 사용 상단 앱 바는 현재 화면의 정보와 작업을 표시하기 위해 앱 창 상단을 따라 일관된 위치를 제공합니다. 그림 1. 상단 앱 바의 예 프래그먼트를 사용할 때 앱 바는 호스트 활동 또는 프

developer.android.com

 

1. 앱바 메뉴 설정하기

일단 앱바에 띄울 메뉴를 설정하기 위해 menu.xml 파일을 만들었다.

(menu.xml 파일은 res 디렉토리 내에 menu라는 디렉토리를 만들고 그 안에 생성하면 된다)

 

menu.xml

<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <item android:id="@+id/action_save"
        android:icon="@drawable/icn_save"
        android:title="@string/action_save"
        app:showAsAction="always" />

    <item android:id="@+id/action_load"
        android:icon="@drawable/icn_load"
        android:title="@string/action_load"
        app:showAsAction="always" />

    <item android:id="@+id/action_share"
        android:icon="@drawable/icn_share"
        android:title="@string/action_share"
        app:showAsAction="always" />
</menu>

icon과 title은 이름만 봐도 뭔지 알 것이고

나는 아이콘이 항상 보이게 하고 싶어서 showAsAction을 always로 주었다.

 

 

2. Activity에 표시하기 + 클릭할 때 액션 주기

menu.xml을 작성한 다음 MainActivity.kt로 와서 

onCreateOptionsMenu 메소드를 오버라이딩해준다.

override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu, menu)
        return true
    }

마지막을 return true로 해 줘야 메뉴바가 보인다고 한다.

 

두 번째로 메뉴를 선택했을 때의 액션을 설정하기 위해 

onOptionsItemSelected를 오버라이딩한다

override fun onOptionsItemSelected(item: MenuItem): Boolean {
        return when(item.itemId) {
            R.id.action_save, R.id.action_load, R.id.action_share -> {
                Toast.makeText(this, item.title, Toast.LENGTH_SHORT).show()
                true
            }
            else -> super.onOptionsItemSelected(item)
        }
    }

item을 받아서 item의 title을 토스트로 출력하도록 하였다.

 

마지막으로 앱 바에서 Title 텍스트를 숨겨주기 위해서

onCreate의 setContentView 아래에 아래와 같이 추가한다.

supportActionBar?.setDisplayShowTitleEnabled(false)

만약 로고를 넣고 싶다면 아래처럼 설정한다. (같은 애들 쭈루룩 하는 거라 스코프 함수 사용햇음)

supportActionBar?.apply {
    setLogo(R.mipmap.ic_launcher_round)	//로고 이미지 지정
    setDisplayUseLogoEnabled(true)	//얘가 true로 해야 로고 보임
    setDisplayShowHomeEnabled(true)	//얘를 true로 해야 로고 보임22222
}

 

3. 다국어 지원

위의 menu.xml를 보면 title을 string 리소스로 사용하는 것을 볼 수 있다.

다국어 지원을 위해 그렇게 처리하였다. (다른나라 사람들이 과연 다운로드 받을지는 일단 논외로..)

다국어 지원을 위해서는 values 폴더를 따로 만들어주어야한다.

 

values-ko-rKR의 strings.xml에는 한글로 된 문자열을 써 두고

values의 string.xml에는 영어로 된 문자열을 써 두면

기기에 설정된 언어에 따라서 자동으로

언어가 한국어일때는 'values-ko-rKR'에서 리소스를 불러오고

다른 언어일 때는 values에서 리소스를 불러오게 된다.

 

와! 날먹!

 


오늘은 피그마로 시안 만드는 게 오래 걸려서 코드는 많이 만지지는 못했다.

차근차근 만들어서 내 이름 들어간 앱 하나라도 만들어봐야지 ㅜ.ㅜ 

 

출처 : stackoverflow.com/a/29036233/14370831

 

Android: Unable to clear initial draw to SurfaceView

I've just started playing around with developing an Android app and have run into some troubles. The intention of this testing app is to draw a square to the screen that moves towards the bottom r...

stackoverflow.com

 

화면 전체에 꽃을 뿌려줘야 할 일이 생겼다.

처음에는 그냥 View로 만들었다가..

이런 건 SurfaceView로 만들어줘야한다는 말을 듣고 SurfaceView를 상속받도록 수정하였음.

 

그런데...

 

 

왜인진 모르겠으나 맨 처음에 찍혔던 게 사라지지 않고 남아있는 것이다!

 

뭐지? 하면서 스택오브플로우를 열심히 찾았는데..

 

답은 허탈할 정도로 간단했음.

 

 

보통 SurfaceView에 애니메이션을 줄 때 코드를 이런 식으로 짤 것이다.

화면에 뭔가를 표시하려고 draw 메소드를 오버라이딩하는데..

 

draw메소드를 오버라이딩하지 않고 그냥 다른 이름으로 메소드를 만들어서 사용하면 된다.

 

 

 

 

허무할 정도 -_- .. 

검색하면 여러 방법이 있는데

 

1.

[Build]-[Clean Project] 하기

 

2. 

[File]-[Sync Project with Gradle Files] 하기

 

3. 

settings.gradle에 있는 내용 지우고 Gradle Sync 한 다음

다시 settings.gradle의 내용 복원시키고 Gradle Sync 하기

 

4.

모듈의 build.gradle 에 들어가서

맨 윗부분이 apply plugin: 'com.android.application' 인지 확인하기

 

5. 

Project를 닫았다가 Open Project가 아니라 Import Project를 통해서 불러오기

stackoverflow.com/a/21295700/14370831

 

Android Studio: Module won't show up in "Edit Configuration"

I've imported a project to Android Studio with several subprojects. I want to run a subproject. I successfully made this subproject's build.gradle as a module. In order to run it, I went to R...

stackoverflow.com

 

난 세시간 헤매다가 5번으로 해결했음 ㅠㅠ

 

+ Recent posts