[英]Custom View Calendar (TableLayout) is extremely slow
I have created a Calendar Custom View from scratch.我从头开始创建了一个日历自定义视图。 The reason I don't use the
CalendarView
is that I want to customize it myself.我不使用
CalendarView
的原因是我想自己自定义它。 I need a few functions that the CalendarView
doesn't have.我需要一些
CalendarView
没有的功能。 So I built a CustomView:所以我建立了一个CustomView:
calendar.xml:日历.xml:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:color/transparent"
android:id="@+id/calender">
<TextView
android:id="@+id/calender_text_view_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="@id/calender_button_next_month"
app:layout_constraintBottom_toBottomOf="@id/calender_button_next_month"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:textColor="@color/colorPrimary"
android:textSize="20sp"
/>
<ImageButton
android:id="@+id/calender_button_next_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintHorizontal_bias="0.8"
app:layout_constraintTop_toTopOf="parent"
android:src="@drawable/ic_navigate_next_colorprimary_36dp"
android:background="@android:color/transparent"
android:contentDescription="@null"/>
<ImageButton
android:id="@+id/calender_button_prev_month"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintHorizontal_bias="0.2"
android:src="@drawable/ic_navigate_before_colorprimary_36dp"
android:background="@android:color/transparent"
android:contentDescription="@null"
/>
<TableLayout
android:id="@+id/calender_table_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/calender_text_view_month"
android:layout_marginTop="30dp"
android:divider="@drawable/recyclerview_divider"
android:showDividers="middle"
android:background="@drawable/table_stroke_color_primary"
/>
</merge>
Calendar.java: (Here I have deleted a few methods that are not important, like getDaysOfMonth
. This is just a little bit of math) Calendar.java:(这里我删除了一些不重要的方法,比如
getDaysOfMonth
。这只是一点点数学)
public class Calender extends ConstraintLayout {
private TextView tvMonth;
private TableLayout calender;
private int year;
private int month;
private Calendar c;
private int selectedDay = -1;
private int selectedMonth = -1;
private int selectedYear = -1;
private Context context;
public Calender(Context context) {
this(context, null);
}
public Calender(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public Calender(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
this.context = context;
LayoutInflater l = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
l.inflate(R.layout.calender, this, true);
tvMonth = findViewById(R.id.calender_text_view_month);
calender = findViewById(R.id.calender_table_layout);
c = Calendar.getInstance();
month = c.get(Calendar.MONTH);
year = c.get(Calendar.YEAR);
makeCalender();
}
private void makeCalender() {
ArrayList<TableRow> rows = new ArrayList<>();
tvMonth.setText(String.format("%s %s", month, year));
calender.removeAllViews();
calender.addView(createCalenderHeader());
int dayOfWeek = getFirstDayOfCurrentMonth();
int daysOfMonth = getDaysOfMonth(month, year);
int daysPrevMonth = month > 0 ? getDaysOfMonth(month - 1, year) : getDaysOfMonth(11, year - 1);
int prevMonth = month > 0 ? month - 1 : 11;
int prevYear = month > 0 ? year : year - 1;
TableRow tr1 = new TableRow(context);
tr1.setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
tr1.setShowDividers(TableRow.SHOW_DIVIDER_MIDDLE);
tr1.setDividerDrawable(ContextCompat.getDrawable(context, R.drawable.table_row_divider));
for (int day = 1; day <= dayOfWeek; day++) {
tr1.addView(createCalenderItemPrev(daysPrevMonth + day - dayOfWeek, prevMonth, prevYear));
}
for (int day = 1; day <= daysOfMonth; day++) {
if((dayOfWeek + day) <= 7) {
tr1.addView(createCalenderItem(day, month, year));
if(dayOfWeek + day == 7)
calender.addView(tr1);
continue;
}
if (rows.size() == 0 ||rows.get(rows.size() - 1).getChildCount() == 7) {
rows.add(new TableRow(context));
rows.get(rows.size() - 1).setShowDividers(TableRow.SHOW_DIVIDER_MIDDLE);
rows.get(rows.size() - 1).setDividerDrawable(ContextCompat.getDrawable(context, R.drawable.table_row_divider));
rows.get(rows.size() - 1).setLayoutParams(new TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT));
}
rows.get(rows.size() - 1).addView(createCalenderItem(day, month, year));
}
c.set(year, month, daysOfMonth);
int lastDayOfMonth = c.get(Calendar.DAY_OF_WEEK);
if(lastDayOfMonth != 1) {
int nextMonth = month < 11 ? month + 1 : 0;
int nextYear = month < 11 ? year : year + 1;
for (int i = lastDayOfMonth; i <= 7; i++) {
rows.get(rows.size() - 1).addView(createCalenderItemPrev(i - lastDayOfMonth + 1, nextMonth, nextYear));
}
}
for(int i = 0; i < rows.size(); i++) {
calender.addView(rows.get(i));
}
}
private CalenderItem createCalenderItem(int day, int month, int year) {
CalenderItem item = new CalenderItem(context);
item.setDate(day, month, year);
item.setOnItemClickedListener(new CalenderItem.IItemClicked() {
@Override
public void itemClicked(int day, int month, int year) {
selectedDay = day;
selectedMonth = month;
selectedYear = year;
makeCalender();
}
});
return item;
}
private CalenderItem createCalenderItemPrev(int day, int month, int year) {
CalenderItem item = new CalenderItem(context);
item.setDate(day, month, year);
return item;
}
}
calendar_item.xml: calendar_item.xml:
<merge
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:clickable="true"
android:focusable="true"
>
<TextView
android:id="@+id/text_view_calender_item_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="4dp"
android:clickable="false"
android:textAlignment="center"
/>
<TextView
android:id="@+id/text_view_calender_item_routine"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/text_view_calender_item_date"
android:layout_marginBottom="4dp"
app:layout_constraintBottom_toBottomOf="parent"
android:clickable="false"
android:textAlignment="center"
/>
</merge>
CalendarItem.java: (Again, I deleted the parts that are not important) CalendarItem.java:(再次删除不重要的部分)
public class CalenderItem extends ConstraintLayout {
private final TextView tvDate;
private final TextView tvRoutine;
private IItemClicked listener = null;
public void setOnItemClickedListener(IItemClicked listener) {
this.listener = listener;
}
public CalenderItem(Context context) {
this(context, null);
}
public CalenderItem(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public CalenderItem(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
LayoutInflater l = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
l.inflate(R.layout.calender_item, this, true);
tvDate = findViewById(R.id.text_view_calender_item_date);
tvRoutine = findViewById(R.id.text_view_calender_item_routine);
setLayoutParams(new TableRow.LayoutParams(0, TableRow.LayoutParams.WRAP_CONTENT, 1));
setBackgroundResource(R.drawable.background_calender_item);
setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
if(listener != null) {
listener.itemClicked(day, month, year);
}
}
});
}
public interface IItemClicked {
void itemClicked(int day, int month, int year);
}
}
This Calendar Custom View works.此日历自定义视图有效。 Every Item is where it should be.
每个项目都在它应该在的地方。 But the thing is that it takes extremely long to build, up to a second or two.
但问题是构建需要非常长的时间,最多一两秒。 Everytime I open the fragment with the calendar, the app freezes for one or two seconds.
每次我用日历打开片段时,应用程序都会冻结一两秒钟。 I can't explain why this is.
我无法解释为什么会这样。
I can edit the implementation or some other code if you want.如果需要,我可以编辑实现或其他代码。 But I think that is everything what's important.
但我认为这才是最重要的。
You can improve your custom CalendarView
by using RecyclerView
instead of TableView
.您可以使用
RecyclerView
而不是TableView
来改进您的自定义CalendarView
。 And using RecyclerView
will give you more ability to customize date cells (select/deselect, select range, etc.), support scrolling, swipe, etc.并且使用
RecyclerView
会给你更多的自定义日期单元格的能力(选择/取消选择、select 范围等),支持滚动、滑动等。
Or you can use this library , which provide highly customizable CalendarView
或者你可以使用这个库,它提供了高度可定制的
CalendarView
Okay, I will answer the question myself, because I managed to solve the issue.好的,我会自己回答这个问题,因为我设法解决了这个问题。 It is so slow, because is is rendering more then 30
CalenderItem
s everytime, which contain of a LinearLayout
and two TextView
s.它是如此缓慢,因为每次渲染超过 30 个
CalenderItem
,其中包含一个LinearLayout
和两个TextView
。 I changed this to just one TextView
with an "\n" to make it look like two TextView
s.我将其更改为只有一个带有“\n”的
TextView
,使其看起来像两个TextView
。 So I could also remove the Layout and just extend TextView
Class.所以我也可以删除布局并扩展
TextView
Class。 So now, it has to render more than 30 TextView
s and Layouts less then before, which makes it way faster.所以现在,它必须渲染超过 30 个
TextView
和比以前更少的布局,这使得它更快。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.