DevBytes: ListView Cell Dragging and Rearranging

ALAN SHANSKE : 안녕하세요, 제 이름은 Alan Shanske입니다 저는 Google의 Android 팀의 인턴입니다

그리고 오늘 저는 Listview 드래그에 대해 이야기 할 것입니다 애니메이션 그래서 오늘 데모는 간단한 Listview가 될 것입니다 아이템을 길게 클릭 한 다음 드래그 할 수 있습니다 그리고 아이템을 드래그 할 때 주위를 드래그하면 실제로 대체하고 이동하고, 기본 다른 Listview 항목과 함께 데이터 집합

그래서이 애니메이션을하는 주된 트릭은 우리가 목록의 견해를 실제로 옮기고 있지 않다는 것을 하지만 당신이 할 일은 비트 맵을 만드는 것입니다 drawable, 위에 비트 맵 drawable 오버레이 Listview, 그리고 당신의 손가락을 드래그하는 동안, 실제로 일어날 일은 우리가 움직일 것이라는 것입니다 비트 맵 drawable, 실제로는 뷰는 아니다 Listview 안에 포함되어 있습니다 그럼 바로 데모로 건너 뛰십시오

여기 치즈 목록 만 있습니다 도착하기 위해 아이템 중 하나를 클릭하여 고정 할 수 있습니다 그것을 잡고, 우리가 그것을 주위로 끌고 갈 때 당신은 그것을 볼 것입니다 주변의 아이템들은 스와핑하면서 움직입니다 기본 데이터 세트가 변경되어 주변을 돌아 다니고 있습니다

또한, 비트 맵 드로어 블이 가능한 경우, 호버 뷰 우리가 가지고있는 것은 Listview의 범위를 벗어납니다 Listview가 스크롤을 시작하고 우리가 필요로하는 요소를 교환하는 같은 시간 똑같은 일이 Listview의 가치 당신이 그것을 놓아 주면, 그 아이템은 Listview에 배치하고 일반 Listview 상호 작용이 일어난다 코드로 바로 넘어 갑시다

여기에서 볼 수있는 주 파일은 Dynamic Listview입니다 Listview 객체를 확장합니다 그리고 아래로 스크롤하면 볼 수있는 첫 번째 중요한 것입니다 OnLongClick 항목 수신기를 추가 한 것입니다 따라서 항목이를 통해 선택되면 어떻게됩니까? LongClick 이벤트 우리는 몇 가지 일을해야합니다

하나, 우리는 그 위치가 무엇인지 결정해야합니다 ClickDown 이벤트, 우리는 어떤 아이템이 선택한 다음 우리는 또한 [INAUDIBLE] 해당 지점에서 선택한보기뿐만 아니라 우리가 관련시키는 아이템 그러면 중요한 일이 있습니다 이 메서드는 GetAndAddHoverView를 호출합니다 비트 맵 드로어 블을 반환합니다

그리고 그것이하는 것은 뷰의 내용을 포착하는 것입니다 그것이 선택되었고, 그것의 스크린 샷을 취하고, 우리가 보았던 주위의 작은 검은 경계, 바로 여기에서 GetBitmapWithBorder, 스크린 샷이 오른쪽 캡처됩니다 여기 GetBitmapFromView 그래서 우리는 비트 맵을 포착하고 그것을 비트 맵에 삽입합니다 비트 맵 드로어 블, 중요한 점은 비트 맵 drawables에는 경계의 관념이있다

그래서 경계를 수정함으로써 위치를 수정할 수 있습니다 그리고 Listview 위에 그릴 때 움직일 것입니다 경계가 어떻게 업데이트되는지에 따라 OK, OnLongItemClick 리스너로 이동하면 주의해야 할 중요한 점은 항목이 LongItemClick 이벤트를 통해 선택된 몇 가지가 있습니다 우리가해야 할 일 하나, 당신은 위치가 무엇인지 결정해야합니다

아래로 이벤트가 발생했습니다 항목 번호를 결정해야합니다 이 선택되었고, 당신은 또한 뿐만 아니라 클릭했다 그래서 우리가 할 일은 호출되는이 메서드를 호출하는 것입니다 GetAndAddHoverView 모든 작업을 수행하면됩니다

보기와 내용이 같은 비트 맵 드로어 블 선정되었습니다 아래의 몇 가지 방법을 사용하여 화면의 내용을 캡쳐하고 검은 색 테두리를 추가한다 당신이 데모에서 본 주위에, 그리고 우리는 모두 던져 버릴거야 그 다음 비트 맵 드로어 블에 우리 Listview 위에 중첩 중요한 점은 비트 맵 드로어 블은 경계의 개념, 그래서 만약 우리가 비트 맵 드로어 블 (Bitmap Drawable) 화면에서 우리가 원하는 곳으로 사용자가 만지십시오

AddHoverView를 얻을 수 있습니다 중요한 점은 보기의 가시성을 확실히해야합니다 이 (가) 선택되었습니다 그래서 여전히 Listview에있게 될 것이고, 비트 맵 Drawable이 Listview를 오버레이 할 것입니다 이 두 객체는 ​​완전히 독립적입니다

사용자 접촉에 응답하여 대응합니다 할 수있는 다른 트릭 이 항목 교환 애니메이션은 언제든지 당신은 단지 당신이 교환하려고하는 아이템을 교환 할 것입니다 그것 바로 위의 항목 또는 바로 아래에 항목이 있습니다 따라서 스왑 애니메이션이 발생할 때마다 또는 드래그 이벤트가 시작되면 항상 위의 항목 ID와 아래의 항목 ID가 있습니다 이 테이블 배열의 안정된 아이템 ID에 대해 True를 반환합니다

어댑터로 구현 된 맞춤 배열 어댑터 인 이 프로젝트, 당신이 근본적으로 말하는 것은 Listview의 모든 항목에는 고유 한 ID가 있습니다 너 자신을 유지하고, 그것은 결코 변하지 않을 것이다 해당 객체 따라서 위의 항목 ID와 아래의 항목 ID는 결코 위 및 아래보기에 대한 변경 사항은 다음과 같습니다 현재 애니메이션

GetViewForID와 여기에 몇 가지 논리가 있습니다 GetPositionForID 내가 실제로 검색 할 수 있었던 곳 일부 품목 ID가 표시된보기 및 그 반대의 경우 당신은 이것을 나중에 좀 더 자세하게 볼 수 있습니다 내가 그걸 어떻게 보았는지 관심있어 그러나 여기서 중요한 점은이 배치 그리기에서 if 그 비트 맵 드로어 블이있을거야 화면에 그려집니다

그래서 내가 여기서하고있는 일, 내가 사건을 끌지 않으면 내 호버 셀이 null이 될 것입니다 아무것도 그리지 않을거야 내 호버 셀이 null이 아닌 객체 인 경우이를 그립니다 내가 처음 전화를 걸면 Listview를 오버레이 할거야 [알아들을 수 없는] 그리고 그 위에 호버 셀을 그립니다

이제 OnTouch 이벤트에는 다음과 같은 몇 가지 사항이 있습니다 수행 할 ActionDown이 발생할 때 나는 아직 알지 못한다 그것은 드래그 이벤트가 될 것인가가 아닌가? 어느 쪽이든 내가 x 좌표와 y 좌표를 검색해야합니다 터치 이벤트

그러면 ActionMove에서 이것이 실제로 사용자가 터치 할 때 셀을 가리 키십시오 첫째, 사용자가 얼마나 많은지에 따라 델타를 계산합니다 이미 손가락을 움직 였고, 그렇다면 참으로 드래그 이벤트에서 나는 내 호버 셀 경계 그래서 여기서 경계를 상쇄하고 범위를 업데이트 한 다음 DispatchDraw를 호출 할 무효화를 호출하고 Listview를 클릭하고 그 위에 호버 셀을 그립니다 내가해야 할 다른 일은 HandleCellSwitch를 호출하는 것입니다

어떤 항목이 있는지 여부를 결정하는 논리입니다 세포 교환이 일어날 것입니다 이 방법의 작동 방식은 몇 군데의 덩어리가 내 움직이는 셀, 비트 맵 드로어 블이든 상관없이 실제로 완전히 겹쳐 지도록 위 또는 아래로 이동했습니다 그 위 또는 아래에있는 셀 그렇다면, 나는 그것을 결정한다

실제로 위로 이동했거나 아래로 내려 가서 아이템 ID를 가져 왔습니다 스왑 될 셀에 해당합니다 그렇게 한 후에는 해당 요소를 기본 데이터 세트가 변경되고 어댑터에 해당 데이터를 알립니다 실제로 변경되었습니다 NotifyDataSetChange 메소드가 실행될 때 일어날 일은 Listview는 데이터가 그것은 레이아웃과 모든것을 호출 할 것입니다

목록보기에서 다시 그려집니다 내가하기 전에, 나는 그 세포들이 보이지 않게 보이게 할 필요가 있고 셀은 여전히 스와핑 중이며 드래그 이벤트는 여전히 있습니다 보이지 않는, 그래서 나는 여기에서 그들을 최신의 것으로 바꾼다 그리고 위와 아래보기를 업데이트합니다 왜냐하면 이제는 데이터에서 소프트 스왑이 실제로 발생했습니다

설정하면 위 또는 아래 셀이 서로 다릅니다 승인 그리고 지금 실제로 가지고있는 가장 중요한 것은 데이터 세트 변경시 애니메이션이 적용된 셀 발생한 이벤트는 OnPreDrawListener입니다 그래서 OnPreDrawListener가하는 것은 당신에게 전화를 돌려줍니다 OnMeasure와 OnLayout 이벤트가 호출 된 후, 결국 모든보기의 값, 모든 위젯의 값 화면이 이미 업데이트되었지만 OnDraw는 업데이트되지 않았습니다

아직 불려왔다 이게 당신이 할 수있는 것은 근본적으로 당신에게 모든 위젯에 대한 모든 최종 값에 액세스 할 수있는 권한 가지고있을 것이다 그러나 실제로 그들이에 끌리기 전에 화면 그래서 최종 결정이 내려지면 여기서 몇 가지 맞춤 그림을 그릴 수 있습니다 값을 가져온 다음이 작업이 완료되면 True를 반환 할 수 있습니다

다른 모든 기본 도면을 실제로 일어난다 이제 OnPreDraw에서 항상 제거하려고합니다 PreDrawListener 한번만 여기에 들어가길 원한다면 그리고 나서 당신이하고 싶은 것은 존재하는 세포를 잡는 것입니다 스왑 된 셀은 드래그하는 셀이 아니라 셀이 새로운 장소로 바꿀 거에요

델타 y로 오프셋합니다 현재 최종 위치에 있지만, 날짜가 변경되기 전의 이전 위치입니다 그래서 우리는 델타 y를 계산합니다 번역을 수행 한 다음 Object Animator를 사용하면됩니다 전환 y를 다시 애니메이션으로 만들려면 약간의 지속 시간을 가진 제로

데모에서 보았 듯이 실제로 달성 할 것입니다 슬라이딩 효과가 발생합니다 아래로 내려 가서 우리는 SwapElements를 가지고 있습니다 기본 데이터 세트를 교환하는 간단한 방법 그리고 나서 TouchesEventsEnded는 유일한 중요한 일입니다

여기에 우리가 생성 한 Object Animator가 있습니다 이 모든 작업은 비트 맵 드로어 블을 애니메이션으로 다시 애니메이션화합니다 사용자가있을 때 Listview의 정확한 위치 전화에서 손가락을 들어 올렸을뿐만 아니라 모두 재설정 우리의 변수는 기본값으로 되돌아갑니다 정말 까다로운 다른 중요한 일은 우리가 실제로 Listview를 가질 수있는 방법 결정하기 스크롤하면서 셀을 드래그하여 모든 위와 아래 항목 ID는 다음과 같이 업데이트됩니다 우리는 그들을 필요로합니다

그래서 여기 HandleMobileScroll에서 우리가 그래서 HandleMobileCellScroll은 매번 호출되는 메소드입니다 사용자가 손가락을 움직일 때 한 번만 여기 방법 이 모든 것은보기에 사용할 수있는 몇 가지 방법을 사용합니다 호버 셀의 경계가 Listview 경계 아래 또는 위 이 경우 SmoothScrollBy를 호출합니다

위 또는 아래로 이동하여 True를 반환합니다 True를 반환하면 우리가 말하는 것은 우리가 스크롤링 상태, 수동 스크롤링 상태에서 그 범위가 Listview의 범위 그리고 그것이 사실이라면, 우리는 스크롤을 한 후에 그것을 알 것입니다 우리가 스크롤을 계속해야하기 때문에 우리는 여전히 수동 스크롤링 상태에 있습니다 호버 셀의 경계

그래서이를 위해 여기에 ScrollListener를 추가합니다 그리고 그것이하는 일은 매번 OnScroll 이벤트입니다 변경되었거나 발생한 경우 첫 번째 또는 ListView의 마지막 보이는 셀이 업데이트되었습니다 그렇다면 새로운 첫 번째 또는 마지막 항목이 위 또는 아래 셀에 대한 잠재적 후보입니다 스왑 된 것입니다

이는 위의 내용을 변경해야한다는 것을 의미합니다 항목 ID 아래에 있습니다 그래서 우리는이 방법들을 여기서 호출하고 스크롤은 HandleMobileScroll을 다시 호출했습니다 그 스크롤 이벤트를 계속 유지하고 전화를 계속 경계가 범위를 벗어나는 한 SmoothScrollBy 목록보기 코드를보고 싶다면 코드를 볼 수 있습니다

더 자세한 내용 하지만 Dynamic Listview를 확장하여 귀하의 프로젝트, 그리고 그 방법을 얻을 수있는 Listview 그런 다음 사용자를 사용하여 동적으로 재 배열 될 수 있습니다 [알아들을 수 없는] 감사