-
반응형
안녕하세요, 하루플 입니다.
최근에 취미로 개발해보고 싶은 앱이 생겨 개발중인데요!
조금 더 깔끔한 UI 개발을 고민하던 중 Expandable Recycler View 라는 것을 보았습니다!
RecyclerView가 기존에 리스트뷰 상위호환 버전이였는데 그걸 접을 수 있게 해주는 겁니다.
아래 예시로 먼저 보겠습니다.
이렇게 띄워주는겁니다!
여기서 작성한 소스코드는 아래 Github에서 다운로드하여 사용하실 수 있습니다.
https://github.com/haruple97/Open-Source-Library
우선, 소스코드 구현전 아래 이미지를 다운로드 하여 drawble 폴더에 넣어줍니다.
circle_plus
circle_minus
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <androidx.recyclerview.widget.RecyclerView android:id="@+id/recyclerview" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout>
list_header.xml
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="horizontal" android:paddingLeft="13dp" android:paddingStart="13dp" android:paddingRight="10dp" android:paddingEnd="10dp" android:paddingTop="5dp" android:paddingBottom="5dp" android:layout_width="match_parent" android:layout_height="wrap_content"> <TextView android:id="@+id/header_title" android:textColor="#045CB1" android:textSize="18sp" android:gravity="center_vertical" android:layout_width="0dp" android:layout_height="match_parent" android:layout_weight="1"/> <ImageView android:id="@+id/btn_expand_toggle" android:src="@drawable/circle_plus" android:layout_width="30dp" android:layout_height="30dp" android:layout_weight="0"/> </LinearLayout>
이제 JAVA 부분을 작성해보겠습니다.
MainActivity.java
public class MainActivity extends AppCompatActivity { private RecyclerView recyclerview; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); recyclerview = findViewById(R.id.recyclerview); recyclerview.setLayoutManager(new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)); List<ExpandableListAdapter.Item> data = new ArrayList<>(); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.HEADER, "모험가 마법사")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "썬콜")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "불독")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "바숍")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.HEADER, "레지스탕스")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "메카닉")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "배틀메이지")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "와일드헌터")); data.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "블래스터")); ExpandableListAdapter.Item places = new ExpandableListAdapter.Item(ExpandableListAdapter.HEADER, "노바"); places.invisibleChildren = new ArrayList<>(); places.invisibleChildren.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "카이저")); places.invisibleChildren.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "카인")); places.invisibleChildren.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "카데나")); places.invisibleChildren.add(new ExpandableListAdapter.Item(ExpandableListAdapter.CHILD, "엔젤릭버스터")); data.add(places); recyclerview.setAdapter(new ExpandableListAdapter(data)); } }
리스트에 추가할 아이템들을 입력해줍니다.
HEADER 속성을 주면 목록의 메인 헤더명으로 사용할 수 있습니다.
ExpandableListAdapter.java
이제 MainActivity에서 추가한 리스트를 받아주는 Adapter를 구현해보겠습니다.
public class ExpandableListAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder>{ public static final int HEADER = 0; public static final int CHILD = 1; private List<Item> data; public ExpandableListAdapter(List<Item> data) { this.data = data; } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int type) { View view = null; Context context = parent.getContext(); float dp = context.getResources().getDisplayMetrics().density; int subItemPaddingLeft = (int) (18 * dp); int subItemPaddingTopAndBottom = (int) (5 * dp); switch (type) { case HEADER: LayoutInflater inflater = (LayoutInflater) parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE); view = inflater.inflate(R.layout.list_header, parent, false); ListHeaderViewHolder header = new ListHeaderViewHolder(view); return header; case CHILD: TextView itemTextView = new TextView(context); itemTextView.setPadding(subItemPaddingLeft, subItemPaddingTopAndBottom, 0, subItemPaddingTopAndBottom); itemTextView.setTextColor(0x88000000); itemTextView.setLayoutParams( new ViewGroup.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); return new RecyclerView.ViewHolder(itemTextView) { }; } return null; } public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { final Item item = data.get(position); switch (item.type) { case HEADER: final ListHeaderViewHolder itemController = (ListHeaderViewHolder) holder; itemController.refferalItem = item; itemController.header_title.setText(item.text); if (item.invisibleChildren == null) { itemController.btn_expand_toggle.setImageResource(R.drawable.circle_minus); } else { itemController.btn_expand_toggle.setImageResource(R.drawable.circle_plus); } itemController.btn_expand_toggle.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (item.invisibleChildren == null) { item.invisibleChildren = new ArrayList<Item>(); int count = 0; int pos = data.indexOf(itemController.refferalItem); while (data.size() > pos + 1 && data.get(pos + 1).type == CHILD) { item.invisibleChildren.add(data.remove(pos + 1)); count++; } notifyItemRangeRemoved(pos + 1, count); itemController.btn_expand_toggle.setImageResource(R.drawable.circle_plus); } else { int pos = data.indexOf(itemController.refferalItem); int index = pos + 1; for (Item i : item.invisibleChildren) { data.add(index, i); index++; } notifyItemRangeInserted(pos + 1, index - pos - 1); itemController.btn_expand_toggle.setImageResource(R.drawable.circle_minus); item.invisibleChildren = null; } } }); break; case CHILD: TextView itemTextView = (TextView) holder.itemView; itemTextView.setText(data.get(position).text); break; } } @Override public int getItemViewType(int position) { return data.get(position).type; } @Override public int getItemCount() { return data.size(); } private static class ListHeaderViewHolder extends RecyclerView.ViewHolder { public TextView header_title; public ImageView btn_expand_toggle; public Item refferalItem; public ListHeaderViewHolder(View itemView) { super(itemView); header_title = (TextView) itemView.findViewById(R.id.header_title); btn_expand_toggle = (ImageView) itemView.findViewById(R.id.btn_expand_toggle); } } public static class Item { public int type; public String text; public List<Item> invisibleChildren; public Item() { } public Item(int type, String text) { this.type = type; this.text = text; } } }
여기까지만 작성하시면 잘 작동되는걸 확인하실 수 있을겁니다!
지금까지는 text만 추가하였지만 저는 text와 imge가 함께 출력되는 CardView 형식으로 개발중입니다.
Adapter에 이미지를 받아주는 속성을 추가하면 될 것 같은데 확실한건 구현해보고 다시 포스팅하겠습니다!
모르거나 궁금한점 있으면 댓글로 부탁드립니다!
반응형'개발 > Android' 카테고리의 다른 글
안드로이드스튜디오 다른 Activity로 값 넘기기 (Intent로 간단하게!) (0) 2021.08.25 안드로이드 스튜디오 TextView 글자 중간 글씨크기, 색깔 바꾸기 (0) 2021.07.30 안드로이드 스튜디오 GIF 파일 재생하기 (1) 2021.07.29 [안드로이드 스튜디오] 앱 처음 사용하는 사용자 확인 (SharedPreferences) (0) 2021.07.29 안드로이드 스튜디오 ViewPager2를 활용한 가로 슬라이더 (2) 2021.07.27 댓글