RecyclerView(Item Click) 2탄
RecyclerView(Item Click) 2탄
public class CountAdapter extends RecyclerView.Adapter<CountAdapter.MyViewHolder>
{
Context mContext;
List<String> items;
String text;
public CountAdapter(Context c, List<String> items, String text)
{
this.mContext = c;
this.items = items;
this.text = text;
}
@Override
public MyViewHolder onCreateViewHolder(ViewGroup viewGroup, int i)
{
View v = LayoutInflater.from(viewGroup.getContext()).inflate(R.layout.recyclerview_custom, viewGroup, false);
return new MyViewHolder(v);
}
@Override
public void onBindViewHolder(final MyViewHolder myViewHolder, int position)
{
final String item = items.get(position);
myViewHolder.tv.setText("" + item);
}
@Override
public int getItemCount()
{
return this.items.size();
}
public class MyViewHolder extends RecyclerView.ViewHolder
{
TextView tv;
public MyViewHolder(View itemView)
{
super(itemView);
tv = (TextView) itemView.findViewById(R.id.tv);
}
}
}
onBindViewHolder에서 setOnClickListener부분 삭제한것 말곤 똑같다.
2. MainActivity.java 작성(천천히 단계별로 작성)
① RecyclerView(rv) 입력하고 .을 써보면 addOnItemTouchListener 라는 것이 있다 넣어보자
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
일단 뭐가 많이 Override 되었는데 어디다가 뭘 써야할지 모르겠다.
이럴때는 역시 맨땅에 헤딩이다.
② 전부 로그를 달고 돌려보자.
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
}
});
③ 앱이 실행되면 List에 몇개 넣어보고 화면을 클릭해본후에 Logcat을 본다
화면을 터치해보니 onInterceptTouchEvent에만 들어갔다.
여기서 뭔가를 처리하면 될 것 같다.
④ 일단 무엇을 넣을지 모르겠으니 Developer사이트를 가서 참조문서를 본다.
참조문서를 보니 Position이라던가 Holder라던가 뭐 Item에 관한걸 먼저 가져와야 할 것같다.
정보를 가져오려면 뭔가 get을 해야하니 RecyclerView의 get부분을 본다.
⑤ getChildAdapterPosition, getChildLayoutPosition, getChildPosition, getChildViewHolder등 눈에 많이 띈다.
그런데 꽁짜로 얻을수는 없다 옆에 (View child)가 적혀있다.. 먼저 View를 구해야 한다.
조금 더 위를 올려보니 View를 구할 수 있다.
findChildViewUnder(float x, float y) x,y값을 주면 된단다.
x,y가 정확히 뭔지 모르니 클릭해봤다.
뭐 수직 수평 위치란다.
옆에 in pixels이란다.
⑥ 안드로이드 스튜디오로 돌아와서 onIntercept 부분을 보자.
역시 안드로이드는 친절하다. MotionEvent e를 사용할 수 있다. 바로 활용해서 써보자.
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
Log.d(TAG, "e.getX==>"+e.getX());
Log.d(TAG, "e.getY==>"+e.getY());
Log.d(TAG, "child==>"+child);
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onTouchEvent");
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
{
Log.d(TAG,"onRequestDisallowInterceptTouchEvent");
}
});
e.getX(), e.getY(),child가
어떻게 들어오는지 모르니 일단 Log로 한번 찍어본다.
처음에 빈공간에 한번 터치했더니 child는 null값,
x,y는 float형의 point index가 나왔다.
두번째는 List의 Item을 선택했더니 child는 LinearLayout값
x,y는 float형의 point index가 나왔다.
세번째는 빈공간을 손가락으로 한번 훑었더니
child는 null값이 나왔다.
이 말은 child가 null값이 아닐때는 터치가
Item위에서 발생했다는 것이다
⑦ 일단 View child를 구했으니 아까 참조문서에서 봤던 쓸만한것들을 다 써본다.
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null)
{
Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));
}
return false;
}
일단 Item이 없는 공간에 클릭했을때에는 if문에 안들어오니 값이 안찍힌다.
다음 1,2번째 Item을 한번씩 터치 해보니 위와 같은 결과가 나왔다.
Adapter,LayoutPosition은 같은 결과가 나왔고
ChildViewHolder는 해당 ViewHolder의 정보가 나왔다.
근데 여기서 한가지 이상한건 분명히 한번 터치했는데 로그캣이 2번씩 찍힌다는 것이다.
이건 Motion e와 관련이 있다. 터치를 계속 하고 있으면 로그캣이 계속 찍힐것이다.
여기서 터치를 하고 손을 땔떼만 값을 얻을 수 있도록 코드를 살짝 더 추가한다.
⑧ GestureDetector 추가
final GestureDetector gestureDetector = new GestureDetector(MainActivity.this,new GestureDetector.SimpleOnGestureListener()
{
@Override
public boolean onSingleTapUp(MotionEvent e)
{
return true;
}
});
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null&&gestureDetector.onTouchEvent(e))
{
Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onTouchEvent");
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
{
Log.d(TAG,"onRequestDisallowInterceptTouchEvent");
}
});
코드를 수정하니 한번 터치당 값 한번이 정확히 들어온다.
여기까지 구한건 position이다.
position만 알아도 일단 원하는 Toast까지는 띄울 수 있다.
⑨ Toast 띄우기
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null&&gestureDetector.onTouchEvent(e))
{
/*Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));*/
Toast.makeText(getApplication(), count.get(rv.getChildLayoutPosition(child)).toString(), Toast.LENGTH_SHORT).show();
//Toast.makeText(getApplication(), count.get(rv.getChildAdapterPosition(child)).toString(), Toast.LENGTH_SHORT).show();
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onTouchEvent");
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept)
{
Log.d(TAG,"onRequestDisallowInterceptTouchEvent");
}
});
지금은 LayoutPosition이든 AdapterPostion이든
원하는것을 사용하면 된다
현재 예제에서는 어떤걸 사용해도 된다.
음 써놓고 보니 .toString()은 빼도 되고 냅둬도 된다.
⑩ 일단 Toast까지는 끝났으나 추가적으로 몇개 더 해본다(ViewHolder편)
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null&&gestureDetector.onTouchEvent(e))
{
/*Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));*/
//Toast.makeText(getApplication(), count.get(rv.getChildLayoutPosition(child)), Toast.LENGTH_SHORT).show();
//Toast.makeText(getApplication(), count.get(rv.getChildAdapterPosition(child)).toString(), Toast.LENGTH_SHORT).show();
Log.d(TAG,"AdapterPosition=>"+rv.findViewHolderForAdapterPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG,"LayoutPosition=>"+rv.findViewHolderForLayoutPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG, "getChildViewHolder=>" + rv.getChildViewHolder(child));
//Toast.makeText(getApplication(), rv.getChildViewHolder(child).itemView.toString(), Toast.LENGTH_SHORT).show();
}
return false;
}
방금은 position으로만 했는데
깜빡했던 getChildViewHolder로 ViewHolder를 구한게 생각난다.
position을 구하고 났으니 참조문서를 더 보자
findViewHolderForAdapterPosition과 findViewHolderForLayoutPosition을 보니
position만 넣어주면 ViewHolder를 구할수 있단다.
한번 구해보고 Log를 찍어본다.
역시 예상대로 3가지 전부 같은 결과가 나온다.
이래서 참조문서를 항상 잘 봐야하는것 같다.
⑪ 자 ViewHolder까지 구했으니 Toast로 Text도 한번 찍어봐야겠다.
혹시 CountAdapter-MyViewHolder class에서 TextView를 선언하고 사용했던 기억이 나는가?
기억이 난다면 비슷하게 써보면 그대로 구할 수 있다.
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener()
{
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e)
{
Log.d(TAG,"onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if(child!=null&&gestureDetector.onTouchEvent(e))
{
/*Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));*/
//Toast.makeText(getApplication(), count.get(rv.getChildAdapterPosition(child)).toString(), Toast.LENGTH_SHORT).show();
Log.d(TAG,"AdapterPosition=>"+rv.findViewHolderForAdapterPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG,"LayoutPosition=>"+rv.findViewHolderForLayoutPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG, "getChildViewHolder=>" + rv.getChildViewHolder(child).itemView);
//TextView tv = (TextView) rv.findViewHolderForAdapterPosition(rv.getChildLayoutPosition(child)).itemView.findViewById(R.id.tv);
//TextView tv = (TextView) rv.findViewHolderForLayoutPosition(rv.getChildLayoutPosition(child)).itemView.findViewById(R.id.tv);
TextView tv = (TextView) rv.getChildViewHolder(child).itemView.findViewById(R.id.tv);
Toast.makeText(getApplication(),tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
return false;
}
3.MainActivity.java 완성
public class MainActivity extends Activity
{
RecyclerView rv;
LinearLayoutManager llm;
List<String> count = null;
Button btn;
EditText et = null;
String text;
private final static String TAG = "ITPANGPANG";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
et = (EditText) findViewById(R.id.et);
rv = (RecyclerView) findViewById(R.id.rv);
btn = (Button) findViewById(R.id.btn);
llm = new LinearLayoutManager(this);
rv.setHasFixedSize(true);
rv.setLayoutManager(llm);
rv.setItemAnimator(new DefaultItemAnimator());
count = new ArrayList<>();
btn.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
text = et.getText().toString();
count.add(text);
rv.setAdapter(new CountAdapter(getApplication(), count, text));
}
});
final GestureDetector gestureDetector = new GestureDetector(MainActivity.this, new GestureDetector.SimpleOnGestureListener() {
@Override
public boolean onSingleTapUp(MotionEvent e) {
return true;
}
});
rv.addOnItemTouchListener(new RecyclerView.OnItemTouchListener() {
@Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
Log.d(TAG, "onInterceptTouchEvent");
View child = rv.findChildViewUnder(e.getX(), e.getY());
if (child != null && gestureDetector.onTouchEvent(e)) {
/*Log.d(TAG, "getChildAdapterPosition=>" + rv.getChildAdapterPosition(child));
Log.d(TAG,"getChildLayoutPosition=>"+rv.getChildLayoutPosition(child));
Log.d(TAG,"getChildViewHolder=>" + rv.getChildViewHolder(child));*/
//Toast.makeText(getApplication(), count.get(rv.getChildAdapterPosition(child)).toString(), Toast.LENGTH_SHORT).show();
Log.d(TAG, "AdapterPosition=>" + rv.findViewHolderForAdapterPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG, "LayoutPosition=>" + rv.findViewHolderForLayoutPosition(rv.getChildLayoutPosition(child)));
Log.d(TAG, "getChildViewHolder=>" + rv.getChildViewHolder(child).itemView);
//TextView tv = (TextView) rv.findViewHolderForAdapterPosition(rv.getChildLayoutPosition(child)).itemView.findViewById(R.id.tv);
//TextView tv = (TextView) rv.findViewHolderForLayoutPosition(rv.getChildLayoutPosition(child)).itemView.findViewById(R.id.tv);
TextView tv = (TextView) rv.getChildViewHolder(child).itemView.findViewById(R.id.tv);
Toast.makeText(getApplication(), tv.getText().toString(), Toast.LENGTH_SHORT).show();
}
return false;
}
@Override
public void onTouchEvent(RecyclerView rv, MotionEvent e) {
Log.d(TAG, "onTouchEvent");
}
@Override
public void onRequestDisallowInterceptTouchEvent(boolean disallowIntercept) {
Log.d(TAG, "onRequestDisallowInterceptTouchEvent");
}
});
}
}
- 개발을 하다보면 평생 한번 사용할 코드와, 몇번 사용할 코드, 늘 사용하는 코드가 있다.
- 평생 한번 사용할 코드를 구해서 사용할때 만약 내가 쓸 기능과 완전히 똑같다면 솔직히 코드 볼 필요도 없다고 생각한다.
- RecyclerView는 ListView가 점차 사라지면서 아마 늘 사용하는 View가 될 것이다.
- 시간이 여유로운 사람들은 직접 테스트 해보면서 RecyclerView의 매력에 빠져보길 권한다.
참고사이트 : http://developer.android.com/intl/ko/reference/android/support/v7/widget/RecyclerView.html
'안드로이드(android) > Recyclerview' 카테고리의 다른 글
RecyclerView(Item Click) 1탄 (0) | 2016.04.06 |
---|---|
RecyclerView.Adapter, ViewHolder(추가) (3) | 2016.04.03 |
RecyclerView.Adapter, ViewHolder (3) | 2016.04.02 |
RecyclerView 기본 (2) | 2016.04.02 |
RecyclerView (0) | 2016.04.01 |