CustomView


CustomView를 사용해서 노래 볼륨을 조절하는 회전식 버튼을 만들어보자.

이번에 만들어볼 커스텀 뷰는 커스텀 이미지 뷰이다.

  • 우선 AppCompatImageView 를 상속받는 코틀린 클래스를 만들자.


// VolumeControlView.kt
class VolumeControlView(context: Context, attr: AttributeSet?) : AppCompatImageView(context, attr) {

    private var mx = 0.0f
    private var my = 0.0f
    private var tx = 0.0f
    private var ty = 0.0f
    private var angle = 0.0f


    // 리스너 객체를 맴버로 포함
    private var listener: VolumeListener? = null    

    // 리스너를 구현한 외부 클래스에서 기능을 사용하게 함 
    interface VolumeListener{
        public fun onChanged(angle: Float):Unit
    }

    // 외부 클래스에서 생성한 리스너를 연결시키는 함수
    fun setVolumeListener(listener: VolumeListener){
        this.listener = listener
    }

    // 현재 각도를 구해주는 함수 (x1: x좌표, y1: y좌표)
    private fun getAngle(x1:Float, y1:Float):Float {
        mx = x1-(width /2.0f)
        my = (height/2.0f)-y1
        return (atan2(mx, my) *180.0f/ PI).toFloat()    // arctan 삼각함수로 각도 계산
    }

    // 터치가 발생하면 
    override fun onTouchEvent(event: MotionEvent?): Boolean {
        return if(event != null){
            tx = event.getX(0)          // 이미지 뷰 기준 현재 x 좌표
            ty = event.getY(0)          // 이미지 뷰 기준 현재 y 좌표
            angle = getAngle(tx,ty)     // 각도
            invalidate()                // onDraw()를 호출
            listener?.onChanged(angle)  // 리스너에서 오버라이딩 된 함수 실행 (사용하는 클래스의 목적에 맞게 구현된 함수) 
            true                        // 성공 반환
        }else false                     // 실패 반환, 부모 함수 실행
    }

    // 화면을 다시 그려줌
    override fun onDraw(canvas: Canvas?) {
        canvas?.rotate(angle, width/2.0f, height/2.0f)  // 이미지 회전
        super.onDraw(canvas)
    }
}


  • 커스텀 이미지 뷰 클래스를 잘 작동했다면 xml에서 만들었던 커스텀 뷰를 사용해보자.


<!--activity_main.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">

    <com.jyh.juyonghan201811567.VolumeControlView
        android:id="@+id/imageView"
        android:layout_width="200dp"
        android:layout_height="200dp"
        android:layout_marginTop="100dp"
        android:src="@drawable/knob"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />


    <ImageButton
        android:id="@+id/stopButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_stop_24"
        app:layout_constraintEnd_toStartOf="@+id/playButton"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="@id/playButton"
        tools:layout_editor_absoluteY="375dp" />

    <ImageButton
        android:id="@+id/pauseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_pause_24"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/playButton"
        app:layout_constraintTop_toTopOf="@id/playButton"
        tools:layout_editor_absoluteY="375dp" />

    <ImageButton
        android:id="@+id/playButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_baseline_play_arrow_24"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@+id/pauseButton"
        app:layout_constraintHorizontal_bias="0.5"
        app:layout_constraintStart_toEndOf="@+id/stopButton"
        app:layout_constraintTop_toBottomOf="@+id/imageView"
        app:layout_constraintVertical_bias="0.182" />

</androidx.constraintlayout.widget.ConstraintLayout>


  • 메인 엑티비티를 작성해 버튼의 각도로 음악 볼륨을 조절할 수 있게 만들어보자.


// MainActivity.kt
class MainActivity : AppCompatActivity() {

    private var mediaPlayer:MediaPlayer? = null
    private var vol = 0.0f

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

        initLayout()    // 레이아웃 초기화
    }

    private fun initLayout() {

        val imageView = findViewById<VolumeControlView>(R.id.imageView)

        // 회전 버튼의 리스너 구현
        imageView.setVolumeListener(object: VolumeControlView.VolumeListener {

            // 현재 각도(angle)를 볼륨으로 변환, 적용
            override fun onChanged(angle: Float) {
                vol = if( angle>0 ) angle/360 else (360+angle)/360
                mediaPlayer?.setVolume(vol,vol)
            }
        })

        // 버튼들 구현
        val playButton = findViewById<ImageButton>(R.id.playButton)
        playButton.setOnClickListener{
            if(mediaPlayer == null){
                mediaPlayer = MediaPlayer.create(this,R.raw.song)
                mediaPlayer?.setVolume(vol,vol)
            }
            mediaPlayer?.start()
        }

        val pauseButton = findViewById<ImageButton>(R.id.pauseButton)
        pauseButton.setOnClickListener {
            mediaPlayer?.pause()
        }

        val stopButton = findViewById<ImageButton>(R.id.stopButton)
        stopButton.setOnClickListener{
            mediaPlayer?.stop()
            mediaPlayer?.release()
            mediaPlayer = null
        }
    }
}