건프의 소소한 개발이야기

[안드로이드] Android RecyclerView with CardView 본문

개발 이야기/안드로이드 이야기

[안드로이드] Android RecyclerView with CardView

건강한프로그래머 2016. 5. 15. 23:28

안녕하세요, 건프입니다. 


이번에는 Android Programming 에서 가장 논란이 많았던 리스트뷰(ListView) 의 대체용으로 발표된 RecyclerView 를 다뤄보겠습니다.



RecyclerView 에서는 예전 ListView 를 제작할 때, 리소스 낭비를 줄이기 위한 Holder 패턴(Pattern) 을, 강제사항으로 만들어두고,

Interface 함수들을 좀 더 목적에 부합하도록 만들어 진 뷰입니다.


1. 어뎁터(Adapter)는 다음과 같습니다.


public class StoreSearchAdapter extends RecyclerView.Adapter<StoreSearchAdapter.ViewHolder> {

Context context;
List<StoreInfo> items;
int item_layout;

public StoreSearchAdapter(Context context, List<StoreInfo> items, int item_layout){
this.context = context;
this.items = items;
this.item_layout = item_layout;
}

@Override
public StoreSearchAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
LayoutInflater inflater = LayoutInflater.from(parent.getContext());
if (viewType == 0) {
View v = inflater.inflate(R.layout.search_store_item_front, null);
return new FrontCardHolder(v);

}else{
View v = inflater.inflate(R.layout.search_store_item_back, parent, false);
return new BackCardHolder(v);
}

}

@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
@Override
public void onBindViewHolder(ViewHolder holder, final int position) {
StoreInfo item = items.get(position);
Log.d("holder.getItemType", holder.getItemViewType()+"");
switch (holder.getItemViewType()){
case 0:
FrontCardHolder fHolder = (FrontCardHolder)holder;
Drawable drawable = context.getResources().getDrawable(item.getImage());
fHolder.image.setBackground(drawable);
// fHolder.card.setOnClickListener(new View.OnClickListener() {
// @Override
// public void onClick(View v) {
// Toast.makeText(context, "position : "+position, Toast.LENGTH_SHORT).show();
// }
// });
fHolder.text.setText(item.getStoreName());
break;
case 1:
BackCardHolder bHolder = (BackCardHolder)holder;
bHolder.text.setText(item.getStoreName());
break;

}

}

@Override
public int getItemCount() {
return this.items.size();
}

@Override
public int getItemViewType(int position) {
return items.get(position).getFlipType();
}

public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener{


public ViewHolder(View itemView) {
super(itemView);
itemView.setOnClickListener(this);
}

@Override
public void onClick(View v) {
int position = getPosition();
Toast.makeText(context, "holder position : "+position, Toast.LENGTH_SHORT).show();
items.get(position).flipCard();
notifyItemChanged(position);
}


}

public class FrontCardHolder extends ViewHolder{

public ImageView image;
public TextView text;
public CardView card;

public FrontCardHolder(View itemView) {
super(itemView);
image=(ImageView)itemView.findViewById(R.id.item_image_front);
text=(TextView)itemView.findViewById(R.id.item_text_front);
card = (CardView)itemView.findViewById(R.id.card_view);
}
}

public class BackCardHolder extends ViewHolder{

public TextView text;

public BackCardHolder(View itemView) {
super(itemView);
text = (TextView) itemView.findViewById(R.id.item_text_back);
}
}
}


RecyclerView.Adapter 를 사용하면, 두개의 콜백함수를 오버라이드 받아야 합니다.


onCreateViewHolder()

onBindViewHolder() 인데


이름과 내부에 들어간 코드를 해석해보면, 새로운 뷰를 생성하는 것은 onCreateViewHolder 에서 작업하고 Holder를 생성해주면

나중에 다시 보여줄때는 재활용해서(Recycle) onBindViewHolder 에서 내용물을 그리는 것을 알 수 있습니다.


위의 코드는 카드뷰(CardView) 이용할때, 카드의 앞면과 뒷면을 둘 다 작업하려고 만들어진 Adapter 입니다.




2. Build.gradle 의 dependency를 설정해줍니다.


compile 'com.android.support:recyclerview-v7:23.3.0'
compile 'com.android.support:cardview-v7:23.0.+'


버전정보의 약간의 차이는 있을 수 있습니다. 일단 제 프로젝트에서 위 와 같이 사용했을 때, 문제없이 사용하고 있습니다. 



3. 각각의 Xml 입니다.


-  search_store_item_front.xml ( 카드 앞면 레이아웃)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
card_view:cardCornerRadius="3dp"
card_view:cardElevation="3dp"
android:layout_width="match_parent"
android:layout_height="270dp"
android:layout_margin="5dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<ImageView
android:layout_width="match_parent"
android:layout_height="210dp"
android:id="@+id/item_image_front"/>
<TextView
android:id="@+id/item_text_front"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="ddd"/>
</LinearLayout>

</android.support.v7.widget.CardView>


</LinearLayout>


- search_store_item_back.xml (카드 뒷면 레이아웃)


<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:card_view="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.v7.widget.CardView
android:id="@+id/card_view"
card_view:cardCornerRadius="3dp"
card_view:cardElevation="3dp"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_margin="5dp">

<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">

<TextView
android:id="@+id/item_text_back"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="10dp"
android:text="ddd"/>
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/search_store_down"/>
</LinearLayout>

</android.support.v7.widget.CardView>


</LinearLayout>




4. 화면에서의  코드입니다.


public class SearchFragment extends Fragment {

private final String TAG = "SearchFragment";

private CoilApplication app;


public SearchFragment() {
// Required empty public constructor
}


@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {

app = (CoilApplication) getActivity().getApplicationContext();
Log.d(TAG, ""+app.storeAll.getItemList().size());
// Inflate the layout for this fragment
ViewGroup rootView = (ViewGroup) inflater.inflate(R.layout.fragment_search, container, false);

RecyclerView recyclerView = (RecyclerView)rootView.findViewById(R.id.recycler_view);
LinearLayoutManager layoutManager = new LinearLayoutManager(getActivity());
recyclerView.setHasFixedSize(true);
recyclerView.setLayoutManager(layoutManager);

List<StoreInfo> items = new ArrayList<>();
StoreInfo[] item=new StoreInfo[5];
item[0]=new StoreInfo(R.drawable.logo_sample1,"#1");
item[1]=new StoreInfo(R.drawable.logo_sample2,"#2");
item[2]=new StoreInfo(R.drawable.logo_sample3,"#3");
item[3]=new StoreInfo(R.drawable.logo_sample3,"#4");
item[4]=new StoreInfo(R.drawable.logo_sample3,"#5");

for(int i=0;i<5;i++) items.add(item[i]);

recyclerView.setAdapter(new StoreSearchAdapter(getActivity(), items, R.layout.fragment_search));

return rootView;
}

}


불필요한 변수선언은 안하셔도 됩니다. (개인적인 작업하면서 들어간 코드들입니다)



5.  위의 화면의 레이아웃 입니다.

- fragment_search.xml

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.brianandroid.myzzung.coli.ui.SearchFragment">


<android.support.v7.widget.RecyclerView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:clipToPadding="false"/>

</LinearLayout>



6. 결과 화면 입니다


카드뷰가 포함된 형태


카드뷰를 누르면 위와 같이 뒷면이 보입니다.



도움이 되었길 바랍니다 :)

Comments