android

android RecylcerView ImageResize (카카오톡 이미지 커지는 애니메이션 구현 방법)

sieunju 2018. 1. 13. 20:36
반응형


오랜만에 포스팅을 하게 되었습니다. 일단 어떤걸 말하는 건지 이해가 잘 안되는 분들을 위해서 알려드리도록 하겠습니다. 우선 카카x톡을 들어가면 

저 텝이 보이는데 저 텝을 클릭해서 스크롤을 하면 영상이 점점 커져서 보이는 애니메이션 같은게 있습니다. 



 

(이 구현영상은 제가 구현한 것으로 실제 녹화해서 찍은 영상입니다.) 

제가 만든 것은 이미지로 구현했지만 카카x톡에서는 영상으로 되어있습니다. (딱히 상관은 없습니다.)


이제 본론으로 넘어와서 저것이 어떻게 구현되는건지 소스에 대해서 부분부분 보여드리도록 하겠습니다. 


-CustomLinearLayoutManager.java-


-MainActivity.java-

-CustomRecylcerAdapter.java-

-image_resize.xml-


이미지가 커지는 부분만 소스 공개해드렸습니다. 

(기본적으로 RecyclerView 를 만들고 거기에 Adapter 연결하는 거는 할줄 알아야 이 기능을 구현할수 있습니다. 

그럼 소스 해석을 하도록 하겠습니다. )


-CustomLinearLayoutManager

위 소스를 보시면 알겠지만, 변수명이라던지 로직에 대해서 설명을 했습니다. 참고하시면 될거 같습니다. 

그래도 로직에 대해서 설명하도록 하겠습니다. 

@Override
public int scrollVerticallyBy(int dy, RecyclerView.Recycler recycler, RecyclerView.State state) {

for (int i = 0; i < getChildCount(); i++) {
View view = getChildAt(i);
if (view != null && view.getTag() != null) {
//보이는 뷰중에 이미지가 확대되는 뷰일경우 Evt 실행.
if (view.getTag().equals(CustomRecyclerAdapter.RESIZE_TAG)) {
//특정뷰가 움직이는 Y 좌표값.
int viewPosition = (getDecoratedBottom(view) + getDecoratedTop(view)) / 2;
//디바이스 전체 높이.
int allHeight = getHeight();
//시작 지점 밑에서 1/6 , 끝나는 지점 5/6.
double evtStartPosition = allHeight - (allHeight / 6);
double evtFinalPosition = allHeight / 6;
//0부터 디바이스 전체 높이만큼 이벤트 실행.
if (viewPosition > 0 && viewPosition < allHeight) {
if (evtStartPosition >= viewPosition) {
//아래 1/6지점 부터 5/6 까지.
double value = (evtStartPosition - viewPosition) / (evtStartPosition - evtFinalPosition) * 100;
int evtPercentage = (int) value;
mRecyclerAdapter.setResizeHeight(evtPercentage);
}
}
}
}

}
return super.scrollVerticallyBy(dy, recycler, state);
}


이 클래스는 쉽게 말해서 RecylcerView 에서 카드들이 보이는 거에 대해서 이벤트를 구현할수 있도록 도와주는 클래스 입니다. 

안에 오버라이딩되어 있는 함수중에 scrollVerticallBy 라는 함수가 있는데 이 함수는 수직으로 스크롤할때 함수가 호출이 됩니다. 


스크롤을 할때 디바이스에서 노출되는 카드들중에 이미지를 확대해야 하는 "카드" 가 있을경우 이벤트를 실행하도록 합니다. 이때 저같은 경우에는 밑에서 1/6 지점 부터 이벤트가 실행되도록 했습니다. 그 후 최종 적으로 

CustomRecyclerAdapter 클래스로 

0~ XXX% 값이 setResizeHeight 함수를 통해 전달이 됩니다.


-CustomRecyclerAdapter 

위 소스도 마찬가지겠지만, 필요한 부분에 주석을 달았고 알기쉬운 변수명으로 구성했습니다. 

그래도 기본 로직에 대해서 설명하도록 하겠습니다. 


우선 BaseViewHolder 는 기본 카드들의 뷰 홀더 입니다. 이부분은 신경 안쓰셔도 상관 없습니다. 


제가 처음에 CustomLinearLayoutManager 에서 어답터의 setResizeHeight 함수를 통하여 0~XXX%의 값을 Set 한다고 했는데 그 부분이 아래 소스 부분입니다.

/**
* setResize Height
*
* @param value
* @author jsieun
*/
public void setResizeHeight(int value) {
mResizeHeight = value;
}


특정 카드가 원하는 위치에서 보일때 setResizeHeight 함수를 통하여 mResizeHeight 값은 계속해서 Set 이 됩니다.


그후에 ResizeViewHolder 를 그리는 부분에 대하여 설명하도록 하겠습니다. 

저같은 경우에는 5번째에 ResizeViewHolder 가 나오도록 구현했습니다.

if (viewType == VIEWPAGER_TYPE) {
view = LayoutInflater.from(parent.getContext()).inflate(R.layout.image_resize, parent, false);
view.getViewTreeObserver().addOnScrollChangedListener(this);
return new ResizeViewHolder(view);

다른 일반 뷰홀더는 getViewTreeObserver().addOnScrollChangedListener(this); 이 리스너를 안했는데 이미지가 커지는 뷰홀더는 스크롤 리스너를 달았습니다. 그 이유는 

CustomLinearLayoutManager 에서 받는 값을 바로 이미지가 커지는 뷰홀더에 값을 전달할수 없기 때문입니다. 그래서 스크롤 이벤트를 달아서 이미지가 커지는 뷰홀더가 스크롤이 됐을때 


@Override
public void onScrollChanged() {
((ResizeViewHolder) mResizeViewHolder).resizeEvt(mResizeHeight);
}


ResizeViewHolder 클래스 안에 resizeEvt 함수를 호출하도록 구현을 했습니다. 


/**
* 0% ~ 100% 사이즈 크기
*
* @param heightPercentage
* @author jsieun
*/
public void resizeEvt(int heightPercentage) {
//연산 계산 ( 최대값 - 최소값 ) * x% -> y
//y += 최소값 -> 0%~100% 이미지 크기만큼 나온다.
double percentage = (double) heightPercentage / 100;
int value = (int) (mCalculation * percentage);
value += mMinImageHeight;
if (value >= mMaxImageHeight) {
value = mMaxImageHeight;
} else if (value <= mMinImageHeight) {
value = mMinImageHeight;
}

//이미지를 감싸고 있는 Layout의 높이값을 Set
RelativeLayout.LayoutParams layoutParams = new RelativeLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
layoutParams.height = value;
mResizeViewRelativeLayout.setLayoutParams(layoutParams);
//아래에서 위로 스크롤할경우 텍스트색상은 점점 연하게
//위에서 아래로 스크롤할경우 텍스트색상은 점점 진하게
mResizeTextView.setTextColor(Color.parseColor(calculationAlpha(heightPercentage)));
}


그리고 resizeEvt 함수는 이미지의 최소크기와 최대 크기에 맞춰서 사이즈가 계속해서 Set 이 됩니다.

그와 동시에 가운데 텍스트 색상은 하->상 스크롤 할경우 점점 연하게 

상->하 스크롤 할경우 점점 진하게 노출되도록 구현 했습니다. 


이상 소스 해석은 마치도록 하겠습니다. 설명과 소스가 좀 많이 길어서 다시 위로 올려서 구현한 영상을 보기 귀찮은 분들을 위해서 다시 한번 올립니다. 


 

마지막으로 제가 구현한 소스라서 마음대로 가져다가 사용하셔도 상관 없는데, 

댓글은 남기고 사용하시면 정말 감사합니다.^^


Ps. 참고로 이미지가 커질때 나오는 저 이미지 소스는 제가 요새 관심있게 보는 다음 웹툰 홍도 입니다. :D

이만 포스팅을 마치도록 하겠습니다. 




반응형