티스토리 뷰
반응형
SMALL
https://jihunstudy.tistory.com/20?category=807405
기본적인 DrawerLayout 에서 + 전체 화면 + RecyclerView 가로 스크롤 Intercept 조건.
<?xml version="1.0" encoding="utf-8"?> <com.example.customdrawerlayout.CustomView.DrawerLayoutHorizontalSupport xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/drawer_layout" android:layout_width="match_parent" android:layout_height="match_parent"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:gravity="center"> <Button android:id="@+id/btn_menu" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="openMenu"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="테스트 입니다."/> </LinearLayout> <com.example.customdrawerlayout.CustomView.MenuView android:id="@+id/menu_view" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="left" android:background="#FF0000"> </com.example.customdrawerlayout.CustomView.MenuView> </com.example.customdrawerlayout.CustomView.DrawerLayoutHorizontalSupport> | cs |
class MenuView @JvmOverloads constructor ( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : LinearLayout(context, attrs, defStyleAttr) { init { LayoutInflater.from(context).inflate(R.layout.view_menu, this, true) setList() } private fun setList() { list.layoutManager = LinearLayoutManager(context, LinearLayoutManager.HORIZONTAL, false) list.addItemDecoration(PaddingItemDecoration(context, 10, 10)) list.adapter = ListAdapter() } } | cs |
class DrawerLayoutHorizontalSupport @JvmOverloads constructor( context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0 ) : DrawerLayout(context, attrs, defStyleAttr) { private var mRecyclerView: RecyclerView? = null private var mNavigationView: LinearLayout? = null @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) { val widthMode = MeasureSpec.getMode(widthMeasureSpec) val heightMode = MeasureSpec.getMode(heightMeasureSpec) val widthSize = MeasureSpec.getSize(widthMeasureSpec) val heightSize = MeasureSpec.getSize(heightMeasureSpec) if (widthMode != MeasureSpec.EXACTLY || heightMode != MeasureSpec.EXACTLY) { throw IllegalArgumentException( "DrawerLayout must be measured with MeasureSpec.EXACTLY." ) } setMeasuredDimension(widthSize, heightSize) // Gravity value for each drawer we've seen. Only one of each permitted. val foundDrawers = 0 val childCount = childCount for (i in 0 until childCount) { val child = getChildAt(i) if (child.visibility == View.GONE) { continue } val lp = child.layoutParams as LayoutParams if (isContentView(child)) { // Content views get measured at exactly the layout's size. val contentWidthSpec = MeasureSpec.makeMeasureSpec( widthSize - lp.leftMargin - lp.rightMargin, MeasureSpec.EXACTLY ) val contentHeightSpec = MeasureSpec.makeMeasureSpec( heightSize - lp.topMargin - lp.bottomMargin, MeasureSpec.EXACTLY ) child.measure(contentWidthSpec, contentHeightSpec) } else if (isDrawerView(child)) { val childGravity = getDrawerViewGravity(child) and Gravity.HORIZONTAL_GRAVITY_MASK if (foundDrawers and childGravity != 0) { throw IllegalStateException( "Child drawer has absolute gravity " + gravityToString(childGravity) + " but this already has a " + "drawer view along that edge" ) } val drawerWidthSpec = ViewGroup.getChildMeasureSpec( widthMeasureSpec, MIN_DRAWER_MARGIN + lp.leftMargin + lp.rightMargin, lp.width ) val drawerHeightSpec = ViewGroup.getChildMeasureSpec( heightMeasureSpec, lp.topMargin + lp.bottomMargin, lp.height ) child.measure(drawerWidthSpec, drawerHeightSpec) } else { throw IllegalStateException( "Child " + child + " at index " + i + " does not have a valid layout_gravity - must be Gravity.LEFT, " + "Gravity.RIGHT or Gravity.NO_GRAVITY" ) } } } private fun isContentView(child: View): Boolean { return (child.layoutParams as LayoutParams).gravity == Gravity.NO_GRAVITY } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) internal fun isDrawerView(child: View): Boolean { val gravity = (child.layoutParams as LayoutParams).gravity val absGravity = Gravity.getAbsoluteGravity( gravity, child.layoutDirection ) return absGravity and (Gravity.LEFT or Gravity.RIGHT) != 0 } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN_MR1) internal fun getDrawerViewGravity(drawerView: View): Int { val gravity = (drawerView.layoutParams as LayoutParams).gravity return Gravity.getAbsoluteGravity(gravity, drawerView.layoutDirection) } override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { mRecyclerView?.let { mRv -> Log.d( "onInterceptTouchEvent", (mRv.layoutManager as LinearLayoutManager).findLastVisibleItemPosition().toString() + "" ) mNavigationView?.let { mNavi -> return if (isInside(ev, mRv) && isDrawerOpen(mNavi)) { if ((mRv.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (mRv.adapter?.itemCount ?: 1) - 1) return super.onInterceptTouchEvent(ev) else false } else super.onInterceptTouchEvent(ev) } } return super.onInterceptTouchEvent(ev) } private fun isInside(ev: MotionEvent, mRv: RecyclerView): Boolean { //check whether user touch recylerView or not return ev.x >= mRv.left && ev.x <= mRv.right && ev.y >= mRv.top && ev.y <= mRv.bottom } operator fun set(navigationView: LinearLayout, recyclerView: RecyclerView) { mRecyclerView = recyclerView mNavigationView = navigationView } companion object { private val MIN_DRAWER_MARGIN = 0 // dp internal fun gravityToString(gravity: Int): String { if ((gravity and Gravity.LEFT) == Gravity.LEFT) { return "LEFT" } return if ((gravity and Gravity.RIGHT) == Gravity.RIGHT) { "RIGHT" } else Integer.toHexString(gravity) } } } | cs |
아래 코드 참고
Custom 된 DrawerLayout 의 문제점이라고 한다면
가로 스크롤 되는 RecyclerView 가 있다고 가정 했을 때, findLastVisibleItemPosition() 으로 체크를 해서 그런지, 스크롤 중 마지막 아이템이 조금이라도 보인 상태에서
손을 떼고 다시 스크롤을 시도 할 때 TouchEvent 를 DrawerLayout 에 던져 주기 때문에 DrawerLayout 이 닫힌다.
" 스크롤이 완벽하게 끝으로 도달 했을 때 " 를 체크 해야 될 것으로 보인다.
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean { mRecyclerView?.let { mRv -> Log.d( "onInterceptTouchEvent", (mRv.layoutManager as LinearLayoutManager).findLastVisibleItemPosition().toString() + "" ) mNavigationView?.let { mNavi -> return if (isInside(ev, mRv) && isDrawerOpen(mNavi)) { if ((mRv.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (mRv.adapter?.itemCount ?: 1) - 1) return super.onInterceptTouchEvent(ev) else false } else super.onInterceptTouchEvent(ev) } } return super.onInterceptTouchEvent(ev) } | cs |
위 사진 처럼 마지막 아이템이 반만 보이는 상태 임에도 불구 하고 메뉴가 닫히는 현상이 나옴.
반응형
LIST
댓글
반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
- Total
- Today
- Yesterday
링크
TAG
- 갤럭시 워치
- 쏘렌토 하이브리드
- 안드로이드 폴드 대응
- 폴더블 상태 유지
- widget 이미지 로딩
- widget onupdate
- Foldable Event
- aos img url bitmap
- 맥 전용
- 가중치랜덤
- 폰과 워치 페어링
- 풀배열 키보드
- Android
- 프래그먼트 데이터 저장
- 쏘렌토 하이브리드 시그니처
- 역시 키크론이네
- widget onreceive
- widget glide
- Fragment data
- Dot indicator
- RandomColor
- wear os
- 랜덤컬러
- 안드로이드 플립 대응
- widget 만들기
- 웨어러블
- 폴더블 이벤트 받기
- android widget 만들기
- flutter web
- Android Wear Os
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
글 보관함