일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- 안드로이드
- video caching
- ChatGPT
- android
- ExoPlayer
- ListAdapter DiffUtil
- kotlin collection
- ktor api call
- ktor client
- 스피너
- AWS EC2
- kotlin list
- ListAdapter
- llm
- Python
- android custom view
- list map
- DiffUtil.ItemCallback
- doc2vec
- exoplayer cache
- android exoplayer
- android ktor
- 유튜브
- Zsh
- build with ai
- FastAPI
- 시행착오
- 유튜브 요약
- map
- getChangePayload
- Today
- Total
목록TIL - 안드로이드 (33)
버튼 수집상
배경 최근본상품 api를 만드는 대신, 상품을 열람할 때마다 앱 내부에서 열람 히스토리를 갱신시키기로 했다. 내부DB를 써도 됐지만 상품번호 문자열만 저장하면 돼서 Preference 프리퍼런스를 사용했다. 1. 새로운 요소 - 리스트 0번째에 저장 2. 중복되는 요소 - 기존 요소 삭제, 리스트 0번째에 저장 기본 코드 Preference // 리스트 자료형을 직렬화해서 문자열로 저장 var recentProducts: String get() = preferences.getString(KEY_RECENT_PRODUCTS, null) ?: "" set(value) = preferences.edit { putString(KEY_RECENT_PRODUCTS, value) } 최근본상품 중복체크해서 저장 //..

1편에서 ListAdapter에 submitList를 하면서 기존 리스트를 업데이트할 때 리스트 깊은 복사deep copy를 해야 하는 이유에 대해 적었다. 이번엔 ListAdapter DiffUtil의 각 함수를 자세히 알아보겠다. 샘플 코드 전체는 1편에 있다. DiffUtil.ItemCallback 에 구현해야하는 함수 2가지가 있다. areContentsTheSame : 리스트 요소의 객체 주소를 비교한다 areItemsTheSame : 리스트 요소의 필드값을 비교한다 함수 이름만 보면 하는 일이 반대가 돼야할 것 같은데 아무튼 그렇다. areItemsTheSame에서 변경사항을 감지하고 싶은 값을 비교해서 UI를 업데이트할 수 있다. 예제 데이터 SimpleObject의 isChecked 값을 ..

배경 리사이클러뷰에서 부분적으로 UI를 업데이트할 때 (ex: 찜하기) 업데이트한 리스트를 submitList()로 세팅해도 DiffUtil이 제대로 돌아가지 않는 경우가 있었다. 리스트 변경사항을 제대로 감지하는 경우를 알기 위해 샘플 프로젝트를 구성해봤다. 샘플 프로젝트 구조 리스트 아이템을 클릭하면 api를 변경된 index를 호출한 뒤 리스트에 반영. api의 결과로 새 리스트를 뿌리는 구조는 비효율적이라고 판단했다. 참고한 앱도 변경값만 리턴하고 있었다. 샘플 데이터 클래스 data class SimpleObject( var name : String, var isChecked : Boolean = false ) BaseActivity.kt abstract class BaseActivity(lay..
안드로이드 설정 > 접근성 > 시인성 향상 > 애니메이션 삭제 위 설정을 체크하면 불필요한 애니메이션 효과가 사라지면서 성능이 좋아진다. 그러나 앱에 따라서는 애니메이션이 제거되면서 정상동작하지 않는 기능도 있다. var isAnimOff = false val contentResolver = root.context.contentResolver val animatorDurationScale = Settings.Global.getFloat(contentResolver, Settings.Global.ANIMATOR_DURATION_SCALE, 1.0f) if (animatorDurationScale == 0f) isAnimOff = true 시스템상에서 애니메이션이 삭제되었는지 여부를 체크하는 코드. Lott..

RecyclerView 리사이클러뷰에 radius를 적용하는 방법 방법 1. 벡터로 마스킹하기 하얀 바탕에 오리고 싶은 영역을 투명처리한 벡터 이미지를 덧대어서 마스킹을 해봤다. 투명영역이 있는 마스킹 이미지는 벡터로 구현해서 용량을 조금이라도 줄이려고 했다. 대신 앱 바탕색이 하얀색이 아니면 하얗게 드러난다. 뷰포트가 정사각형인 벡터 파일을 직사각형 뷰에 적용시키면 균일하게 꺾이던 모서리 radius의 경사면이 같이 늘어났다. 벡터를 요리조리 만들어봐도 알 수가 없어서 1:1 비율을 유지하는 정사각형 벡터를 양 옆에 적용시켰다. 이 경우엔 아마 커스텀뷰를 만들면 될 것 같다. round_mask_start.xml round_mask_end.xml 간단한 벡터 패스 설명: M0,0 스타트 좌표 h 수평 ..

배경 ViewPager 안쪽 웹뷰에서 가로로 스크롤되는 UI가 있을 때 뷰페이저 페이지가 넘어가는 현상이 있었다. 예시 화면 포인터를 보면 웹뷰의 가로 스크롤 영역을 드래그했을 때 바깥쪽 뷰페이저가 넘어간다. 웹뷰의 가로 스크롤을 따로 읽는 함수는 없어서 onTouchEvent 안에서 터치 좌표로 처리했다. CustomWebView.kt class CustomWebView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyle: Int = 0 ) : WebView(context, attrs, defStyle) { private var oldY = 0f private var oldX = 0f init { // 샘플..
배경 리사이클러 뷰 onScrolled 에서 뷰홀더가 화면에 일정 퍼센트 이상 노출됐을 때 알파값과 translationY 값을 제어해서 부드럽게 나타나는 것처럼 보이는 애니메이션이 적용되어있다. open class CustomRecyclerView @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : RecyclerView(context, attrs, defStyleAttr) { // 애니메이션 제어할 뷰홀더 담아놓는 리스트 private val itemHolders: MutableList = mutableListOf() fun onAddViewHolder(viewHolder: ..

배경 TabLayout의 특정 탭에만 api에서 받아온 이미지를 노출시키면서 기존에는 tab.customView를 세팅해서 탭 뷰를 통째로 새로 그렸다. val tabDataList : List // tab data //.. with (binding) { tabs.setupWithViewPager(viewPager) for (i in 0 until tabs.tabCount) { val tab = tabs.getTabAt(i) val tabData = tabDataList[i] if (!tabData.imgPath.isNullOrEmpty()) { // 이미지 정보가 있을 때만 커스텀뷰로 노출 val imageCustomBinding = ViewGnbImageCustomBinding.inflate(layo..