반응형

안녕하세요. 

첫번째 Project "WGPG"의 ver1.0.0 개발을 끝내고 새로운 프로젝트를 진행중인데, 

프로젝트의 내용중에 Custom Calendar의 내용이 있어, 개발하던중에 막히게 되어 글을 작성하게 되었습니다.

1. 구현하고자 하는 것

ViewPager와 RecyclerView를 이용한 Custom Calendar를 구현하고자 합니다.

아래의 그림을 보시면 이해가 편합니다.

ViewPager의 View들은 각 월의 달력을 보여주고 View 안의 RecyclerView가 각 일을 보여주는 역할을 합니다.

2. 소스코드

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
package com.example.customcalenderexample;
 
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.RecyclerView;
import androidx.viewpager.widget.ViewPager;
 
import android.os.Bundle;
import android.widget.TextView;
 
import java.util.Calendar;
import java.util.GregorianCalendar;
 
public class MainActivity extends AppCompatActivity {
    private TextView tv_month;
    private RecyclerView rv;
    private MainAdapter adapter;
    private GregorianCalendar today = new GregorianCalendar();
 
    private ViewPager vp;
 
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
 
        //ViewPager Calendar
 
        vp = (ViewPager) findViewById(R.id.vp);
        vp.setAdapter(new ViewPagerAdapter(this, today.get(Calendar.YEAR), today.get(Calendar.MONTH)));
 
 
        //RecyclerView Calendar
        //Need to
/*
        tv_month = (TextView)findViewById(R.id.tv_month);
        rv = (RecyclerView)findViewById(R.id.rv);
        adapter = new MainAdapter();
        rv.setLayoutManager(new StaggeredGridLayoutManager(7,StaggeredGridLayoutManager.VERTICAL));
        rv.setAdapter(adapter);
        setCalender();
 */
    }
/*
    private void setCalender(){
        try{
            GregorianCalendar calendar = new GregorianCalendar(today.get(Calendar.YEAR), today.get(Calendar.MONTH), 1);
 
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) -1 ;
            int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
 
            tv_month.setText(Integer.toString(calendar.get(Calendar.YEAR)) + "/" + Integer.toString(calendar.get(Calendar.MONTH)+1) + "/" + Integer.toString(calendar.get(Calendar.DATE)));
 
            for(int i = 0; i < dayOfWeek; i++){
                adapter.addItem(0,0);
            }
            for(int i = 1; i <= max; i++){
                adapter.addItem(1,i);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 */
}
cs

ViewPagerAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
package com.example.customcalenderexample;
 
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.StaggeredGridLayoutManager;
import androidx.viewpager.widget.PagerAdapter;
 
import java.util.Calendar;
import java.util.GregorianCalendar;
 
public class ViewPagerAdapter extends PagerAdapter {
    private Context context;
 
    private TextView tv_month;
    private RecyclerView rv;
    private MainAdapter adapter;
    private GregorianCalendar today = new GregorianCalendar();
    private int year, month, num = 0;
 
 
    public ViewPagerAdapter(Context context, int year, int month){
        this.context = context;
        this.year = year;
        this.month = month;
    }
 
    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        View view = null;
        if(this.context != null){
            LayoutInflater inflater = (LayoutInflater)this.context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
            view = inflater.inflate(R.layout.content_viewpager, container, false);
 
 
            tv_month = (TextView)view.findViewById(R.id.tv_month);
            rv = (RecyclerView)view.findViewById(R.id.rv);
 
            adapter = new MainAdapter();
            rv.setLayoutManager(new StaggeredGridLayoutManager(7,StaggeredGridLayoutManager.VERTICAL));
            rv.setAdapter(adapter);
            setCalender(year,month+num);
            num++;
        }
        container.addView(view);
 
        return view;
    }
 
    @Override
    public int getCount() {
        return 3;
    }
 
    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return (view == (View)object);
    }
 
    private void setCalender(int year, int month){
        try{
            GregorianCalendar calendar = new GregorianCalendar(year, month, 1);
 
            int dayOfWeek = calendar.get(Calendar.DAY_OF_WEEK) -1 ;
            int max = calendar.getActualMaximum(Calendar.DAY_OF_MONTH);
 
            tv_month.setText(Integer.toString(calendar.get(Calendar.YEAR)) + "/" + Integer.toString(calendar.get(Calendar.MONTH)+1));
 
            for(int i = 0; i < dayOfWeek; i++){
                adapter.addItem(0,0);
            }
            for(int i = 1; i <= max; i++){
                adapter.addItem(1,i);
            }
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}
 
cs

MainAdapter.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
package com.example.customcalenderexample;
 
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;
 
import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;
 
import java.util.ArrayList;
 
public class MainAdapter extends RecyclerView.Adapter<MainAdapter.ViewHolder> {
    private ArrayList<MainItem> lists = new ArrayList<>();
 
    private int key;
 
    public class ViewHolder extends RecyclerView.ViewHolder {
        private TextView tv_day;
        private TextView tv_header;
        public ViewHolder(@NonNull View itemView) {
            super(itemView);
 
            tv_day = itemView.findViewById(R.id.tv_day);
            tv_header = itemView.findViewById(R.id.tv_header);
        }
    }
 
    @Override
    public int getItemViewType(int position) {
        key = lists.get(position).getKey();
        switch (key){
            case 0 : return 0;
            case 1 : return 1;
            case 2 : return 2;
        }
        return -1;
    }
 
    @NonNull
    @Override
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        LayoutInflater inflater;
        View view;
        ViewHolder vh;
        switch (viewType){
            case 0 :
                inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.item_empty, parent, false);
                vh = new ViewHolder(view);
                return vh;
 
            case 1 :
                inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.item_day, parent, false);
                vh = new ViewHolder(view);
                return vh;
 
            case 2 :
                inflater = (LayoutInflater)parent.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
                view = inflater.inflate(R.layout.item_header, parent, false);
                vh = new ViewHolder(view);
                return vh;
        }
        return null;
    }
 
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        int viewType = getItemViewType(position);
        MainItem item = lists.get(position);
        switch(viewType){
            case 0 :
                break;
            case 1 :
                holder.tv_day.setText(Integer.toString(item.getDay()));
                break;
            case 2 :
                holder.tv_header.setText(Integer.toString(item.getDay()));
                break;
        }
    }
 
    @Override
    public int getItemCount() {
        return lists.size();
    }
 
    public void addItem(int key, int day){
        MainItem item = new MainItem();
 
        item.setKey(key);
        item.setDay(day);
 
        lists.add(item);
    }
 
}
 
cs

MainItem.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.example.customcalenderexample;
 
public class MainItem {
    private int key;
    private int day;
 
    public int getKey() {
        return key;
    }
 
    public void setKey(int key) {
        this.key = key;
    }
 
    public int getDay() {
        return day;
    }
 
    public void setDay(int day) {
        this.day = day;
    }
}
 
cs

3. 지금까지 해본 것

ViewPager의 Page수를 조정해본 결과 2개의 페이지까지는 강제종료되지 않고 잘 동작하지만,

3개 이상의 페이지에서 Swipe를 2회 이상 하면 꺼지는 현상을 확인했습니다.

4. 내가 생각하는 문제점

 1) 많은 양의 view를 넣어서 과부하 상태가 되었다.

 2) ViewPager의 기존의 문제점을 보완한 것이 ViewPager2라는데 ViewPager2가 해결책이 될 수도 있을 것 같다.

 3) ViewPager의 Adapter에서 RecyclerView의 요소들을 추가하지 말고, View를 ViewPager의 list item으로 주는 방법도 될 수도 있을 것 같다.

반응형

+ Recent posts