정상에서 IT를 외치다

[Android, Indicator] 뷰 페이저에 인디케이터 달기 본문

안드로이드

[Android, Indicator] 뷰 페이저에 인디케이터 달기

Black-Jin 2018. 9. 5. 14:44
반응형

안녕하세요. 블랙진입니다.


이번시간에는  '뷰페이저 만들기' 포스팅에 이어서 인디케이터를 달아볼려고 합니다.


먼저 인디케이터가 무엇인지 봐야겠죠?



위 이미지 처럼 A ~ E 의 5개의 화면을 전환하는데 몇 번째 화면인지를 표시하기 위한 뷰가 인디케이터 입니다.


위 예제를 진행하기에 앞서 이전 "뷰페이저 만들기" 포스팅을 진행해 주셔합니다. 혹은 깃허브 주소에서 예제 파일을 다운받아 주세요.


그럼 간단한 인디케이터를 만드는 법에 대해 포스팅을 시작하겠습니다!!




1. CircleIndicator class 를 새로 만들어 줍니다.

class CircleIndicator: LinearLayout {

private var mContext: Context? = null

private var mDefaultCircle: Int = 0
private var mSelectCircle: Int = 0

private var imageDot: MutableList<ImageView> = mutableListOf()

// 4.5dp 를 픽셀 단위로 바꿉니다.
private val temp = TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP, 4.5f, resources.displayMetrics)

constructor(context: Context) : super(context) {

mContext = context
}

constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {

mContext = context
}

/**
* 기본 점 생성
* @param count 점의 갯수
* @param defaultCircle 기본 점의 이미지
* @param selectCircle 선택된 점의 이미지
* @param position 선택된 점의 포지션
*/
fun createDotPanel(count: Int, defaultCircle: Int, selectCircle: Int, position: Int) {

this.removeAllViews()

mDefaultCircle = defaultCircle
mSelectCircle = selectCircle

for (i in 0 until count) {

imageDot.add(ImageView(mContext).apply { setPadding(temp.toInt(), 0, temp.toInt(), 0) })

this.addView(imageDot[i])
}

//인덱스 선택
selectDot(position)
}

/**
* 선택된 점 표시
* @param position
*/
fun selectDot(position: Int) {

for (i in imageDot.indices) {

if (i == position) {

imageDot[i].setImageResource(mSelectCircle)

} else {

imageDot[i].setImageResource(mDefaultCircle)
}

}

}
}

주석을 참고 하시면 어렵지 않게 이해가 되실겁니다.


위 코드중 createDotPanel 함수를 통해 점의 이미지를 가져오는 부분이 있습니다. 이때 각 점들의 padding 값을 4.5dp로 설정하였습니다. 만약 패딩을 안주면 각 점들이 붙어 있는 현상이 발생하겠죠?


for (i in 0 until count) {

imageDot.add(ImageView(mContext).apply { setPadding(temp.toInt(), 0, temp.toInt(), 0) })

this.addView(imageDot[i])
}

setPadding 을 통해 각 점들의 간격을 설정하였습니다. 이때 temp 값은 4.5dp 를 픽셀로 변경한 값입니다.

코드를 통해 xml 을 수정할 때에는 크기 및 간격은 모두 픽셀로 변경해 주셔야 합니다.




2.  activity_main.xml 에 생성한 커스텀 뷰 CircleIndicator 를 추가해 줍니다.

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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">

<android.support.v4.view.ViewPager
android:id="@+id/vpMainActivity"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent" />

<{package name}.CircleIndicator
android:id="@+id/ciMainActivity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="100dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>

</android.support.constraint.ConstraintLayout>

CircleIndicator 를 하단에서 100dp 떨어진 곳에 추가해주었습니다.

xml 에 커스텀 뷰를 추가해 줄 때에는 해당 뷰(CircleIndicator)의 위치를 전부 적어주어야합니다.




3.  추가해 줄 인디케이터 이미지를 생성해 줍니다.


indicator_dot_off.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">

<solid
android:color="#000"/>

<size
android:height="30dp"
android:width="30dp"/>

</shape>

30dp 크기의 검정색 원입니다.



indicator_dot_on.xml

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">

<solid
android:color="#ff0"/>

<size
android:height="30dp"
android:width="30dp"/>

</shape>

30dp 크기의 노랑색 원입니다.




4. MainActivity 에 인디케이터를 연결해 줍니다.

class MainActivity : AppCompatActivity() {

private val adapter by lazy { MainAdapter(supportFragmentManager) }

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

//init viewpager
vpMainActivity.adapter = MainActivity@adapter

vpMainActivity.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{
override fun onPageScrollStateChanged(p0: Int) {

}

override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {

}

override fun onPageSelected(p0: Int) {
ciMainActivity.selectDot(p0)
}

})

//init indicator
ciMainActivity.createDotPanel(5, R.drawable.indicator_dot_off, R.drawable.indicator_dot_on, 0)
}
}

위와 같이 만들면 5개의 인디케이터가 생성되고 뷰페이저 화면 전환을 표시해 줄 수 있습니다.


위 코드중에서 중요한 부분에 대해 설명 들어가겠습니다.~!



_1.  5개의 점을 가진 인디케이터 생성하기

ciMainActivity.createDotPanel(5, R.drawable.indicator_dot_off, R.drawable.indicator_dot_on, 0)

createDotPanel 를 통해 인디케이터를 초기화 해줍니다. 


5개의 점을 가지고 있고 기본 점의 이미지는 indicaator_dot_off ,  선택된 점의 이미지는 indicator_dot_on 입니다.

그리고 인디케이터를 생성할 때 선택되어질 점의 초기 포지션이 0 이라는 의미입니다.



_2. 뷰페이저의 화면전환에 반응하기

vpMainActivity.addOnPageChangeListener(object : ViewPager.OnPageChangeListener{
override fun onPageScrollStateChanged(p0: Int) {

}

override fun onPageScrolled(p0: Int, p1: Float, p2: Int) {

}

override fun onPageSelected(p0: Int) {
ciMainActivity.selectDot(p0)
}

})

뷰페이저의 addOnPageChangeListener 를 통해 화면 전환시 선택된 포지션 값을 받아올 수 있습니다.

위 오버라이팅 메소드 중 onPageSelected 는 화면 전환이 끝났을 때 해당 포지션을 반환합니다. 받은 포지션 p0 를 selectDot 에 넣어주어 해당 포지션을 선택된 점으로 변환하여 인디케이터 역활을 하게 만듭니다.


3번의 추가해줄 인디케이터 이미지를 원이 아닌 다른 이미지로 변경하면 원하는 모양의 인디케이터를 쉽게 만드실 수 있을 겁니다. 안뇨옹~!



위 예제 완성 코드 입니다.

반응형
Comments