1. 이미지 안에 있고 뒤에 프로그레스바가 감싸져 있는 애니메이션
- 하지만 컨텐츠가 표시되기 전에 항상 로딩 UI가 보이면 조금 과한 느낌을 줄수가 있다.
- ContentLoadingProgressBar는 컨텐츠를 불러오는 속도가 느릴때만 로딩 UI를 보여준다 (ex : API 응답이 느린경우)
(1) drawable 제작
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item android:gravity="center">
<rotate
android:drawable="@drawable/ic_launcher_background"
android:pivotX="50%"
android:pivotY="50%"
android:fromDegrees="0"
android:toDegrees="360"
/>
</item>
<item android:drawable="@drawable/ic_launcher_foreground"
android:gravity="center"/>
</layer-list>
(2) 프로그레스바
<ProgressBar
style="@style/Widget.AppCompat.ProgressBar"
...
android:indeterminateDrawable="@drawable/loading"
android:indeterminateDuration="1000" />
- 500ms 이내에 불러오면 로딩 UI를 보여주지 않고
한번 보여진 UI는 최소 500ms동안 보여준다.
public class ContentLoadingProgressBar extends ProgressBar {
private static final int MIN_SHOW_TIME = 500;
private static final int MIN_DELAY = 500;
public synchronized void show() {
postDelayed(mDelayedShow, MIN_DELAY);
}
public synchronized void hide() {
long diff = System.currentTImeMillis() - mStartTime;
if(diff >= MIN_SHOW_TIME || mStartTime == -1) {
setVisibility(View.GONE)
}
else {
postDelayed(mDelayedHide, MIN_SHOW_TIME - diff);
}
}
}
2. ProgressBar 와 Drawable를 이용하여, Progress Animation을 만듬
재생, 녹음/녹화, 다운로드 등에 사용 가능하다.
(1) 바깥쪽 프로그레스바
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<shape android:shape="ring"
android:thickness="5dp"
android:useLevel="false">
<solid android:color="#ffffff" />
</shape>
</item>
<item android:drawable="@drawable/ic_launcher_foreground"
android:gravity="center"/>
</layer-list>
(2) 안쪽 프로그레스바
<?xml version="1.0" encoding="utf-8"?>
<rotate xmlns:android="http://schemas.android.com/apk/res/android"
android:fromDegrees="270"
android:toDegrees="270">
<shape android:shape="ring"
android:thickness="5dp"
android:useLevel="true">
<solid android:color="@color/colorPrimary"/>
</shape>
</rotate>
(3) xml
<ProgressBar
style="@style/Widget.AppCompat.ProgressBar.Horizontal"
android:layout_width="150dp"
android:layout_height="150dp"
android:indeterminate="false"
android:progressDrawable="@drawable/file_down_2"
android:background="@drawable/file_down"
android:max="500"
tools:progress="200" />
3. Frame Animation
로딩 UI를 Frame Animation 으로 보여주고 싶다면
AnimationDrawable을 이용하여 손쉽게 구현 가능 (아래 사진이 계속 반복되는 형태)
(1) 애니메이션 제작 (drawable)
<animation-list xmlns:android="http://schemas.android.com/apk/res/android"
android:oneshot="false">
<item android:drawable="@drawable/ic_launcher_foreground"
android:duration="500" />
<item android:drawable="@drawable/ic_launcher_foreground"
android:duration="500" />
<item android:drawable="@drawable/ic_launcher_foreground"
android:duration="500" />
<item android:drawable="@drawable/ic_launcher_foreground"
android:duration="500" />
<item android:drawable="@drawable/ic_launcher_foreground"
android:duration="500" />
</animation-list>
(2) 적용
<ImageView />
val drawable: AnimationDrawable = ...
imageView.setImageDrawable(drawable)
drawable.start()
drawable.stop
- 지금같은 내용은 좀 지저분해질수 있어서 아래 의 클래스를 이용하는걸 추천
<com.example.widget.AnimationImageView
android:src="@drawable/frame_loading" />
(2-1) 예시코드 (kt)
class AnimatedImageView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null
) : AppCompatImageView(context, attrs) {
private var anim: AnimationDrawable? = null
private var isAttached: Boolean = false
// Tracks the last image that was set, so that we don't refresh the image if it is exactly
// the same as the previous one. If this is a resid, we track that. If it's a drawable, we
// track the hashcode of the drawable.
private var drawableId: Int = 0
private fun updateAnim() {
val drawable = drawable
if (isAttached) {
anim?.stop()
}
if (drawable is AnimationDrawable) {
anim = drawable
if (isShown) {
drawable.start()
}
} else {
anim = null
}
}
override fun setImageDrawable(drawable: Drawable?) {
if (drawable != null) {
if (drawableId == drawable.hashCode()) return
drawableId = drawable.hashCode()
} else {
drawableId = 0
}
super.setImageDrawable(drawable)
updateAnim()
}
override fun setImageResource(resid: Int) {
if (drawableId == resid) return
drawableId = resid
super.setImageResource(resid)
updateAnim()
}
override fun onAttachedToWindow() {
super.onAttachedToWindow()
isAttached = true
updateAnim()
}
override fun onDetachedFromWindow() {
super.onDetachedFromWindow()
anim?.stop()
isAttached = false
}
override fun onVisibilityChanged(changedView: View, vis: Int) {
super.onVisibilityChanged(changedView, vis)
if (isShown) {
anim?.start()
} else {
anim?.stop()
}
}
}
4. Notification Icon
- API 21 이상 가능
<animation-list android:oneshot="false">
<item
android:drawable="@drawable/stat_sys_download_anim0"
android:duration="200"/>
<item
android:drawable="@drawable/stat_sys_download_anim1"
android:duration="200"/>
...
</animation-list>
Notification.Builder(...)
.setSmailIcon(R.drawable.stat_sys_download)
...
.build()
'ANDROID' 카테고리의 다른 글
Android UI - Animation (Transition) (0) | 2020.09.27 |
---|---|
Android UI - Animation (Button) (0) | 2020.09.27 |
ViewModel + LiveData + DataBinding 을 적용 해보자 (0) | 2020.08.17 |
간단하게 RecyclerView 를 달아보자 (0) | 2020.07.31 |
Retrofit2 + Okhtttp3 를 이용하여 데이터를 달아보자 (0) | 2020.03.01 |