Androidで高カスタマイズカレンダーコントロールを実現
19521 ワード
Androidで高カスタマイズカレンダーコントロールを実現
このコントロールはGitHub上のカレンダー項目に基づいて、高度にカスタマイズされた修正版です.そのため、元の項目の住所を添付します.https://github.com/SundeepK/CompactCalendarView既存のコントロールに基づいてヘッダーを追加する月表示 は、データの日付に応じて異なるスタイルを表示する を追加する.データ日付によるイベント を追加する.クリック外部非表示カレンダー効果 を追加クリックイベント を追加 Android高カスタマイズカレンダーコントロールを実現
概要 カスタムヘッダの実装 ヘッドビュー を追加ヘッダクリックイベント を追加
カレンダコントロールにデータを追加データに基づいて表示スタイルを変更 コントロールにデータを追加 データ制御カレンダー関連表示 クリックイベント を追加
補足説明 コントロールアニメーションに関する質問 初期隠蔽に関する問題 クリックコントロール以外の場所でカレンダーコントロールを隠す実装 について CompactCalendarViewの作者 に感謝
概要
CompactCalendarViewは、カレンダーのデフォルト当日および他の日付を選択する表示、スライドイベント、クリックイベントなどの機能を実現し、非常に完全なオープンソースプロジェクトです.--[プロジェクトアドレス]
しかし、開発の必要性に介在して、まだ多くの機能が実現されていないので、ここで詳細なカスタマイズの需要を説明して、あなたを助けることができることを望んでいます.
文章コントロールの原型はCompactCalendarViewを使用し、多くの使いやすい機能を拡張しています.元のコントロール機能の使用方法は、Githubを参照してください.
カスタムヘッダの実装
CompactCalendarView:プロジェクトを開くとパッケージ化されたviewであることがわかります具体的な操作はCompactCalendarControllerクラスに渡されました
主な方法は次のとおりです.
void drawMonth(Canvas canvas, Calendar monthToDrawCalender, int offset)
このメソッドの最初のパラメータは言うまでもなく、分からない場合はカスタムviewのOnDrawメソッドをご自身でご理解ください
2番目のパラメータは、特定の日付を判断するために使用されます.
3番目のパラメータはオフセット量を表すために使用されます(このオフセット量はスライドイベントのオフセット量を指します).
主なロジック:
上記のコードから明らかなように、これは7行7列のマトリクスを描き、最初の行は曜日を表示します.
スペースにヘッドビューを追加するにはここで文章を書かなければなりません
ヘッドビューの追加
ここでは簡単に頭を描き、現実の年月のテキストと月を切り替えるためのボタンを2つ描き、drawMonthメソッドにこのメソッドを配置し、頭の位置を予約して具体的なコードを以下のように変更します.
これにより、私たちの頭部がビューに表示され、このコントロールは全体的に1つの頭部の距離を下に移動することに相当し、すべてのクリックイベントが錯乱するので、私たちの対応するクリックイベントを追加するついでに、既存のクリックイベントを校正します.
ヘッドクリックイベントの追加
まず自分で追加した頭部のクリックイベントを書いて、コードは以下の通りです.
私は左右の2つのボタンを3列目と5列目の位置に配置しました.自分のニーズに合わなければ、自分で修正することができます.その後、私たちのクリックイベントを既存のクリックイベントに追加し、クリックイベントの乱れ問題を修正します.
ここまでヘッダの追加が完了しました.
カレンダコントロールにデータを追加し、データに基づいて表示スタイルを変更します.
私たちはこのような需要があると仮定して、私たちは毎日のデータをローカルに保存して、その日ローカルにデータがあればクリックして相応のデータを取り出すことができて、しかもオプションの日付は黒で、オプションの日は灰色です.このようなニーズは、カレンダーコントロールとデータをバインドする必要があります.では、まずデータから始めましょう.
コントロールにデータを追加するには、次の手順に従います.
この方法をCompactCalendarViewに公開しました
これにより、データが入力されると、関連する操作が可能になります.
データに基づいてカレンダ関連の表示を制御
それとも描画方法に戻るか、
ここで筆者は現在表示されている月のみについて操作するので、ここでelse ifコードを追加すると以下のようになります.
ここではフォントの色を変えたと判断するだけで、集合を巡る方法で対応するデータを探すのは理想的ではありませんが、仕方なく筆者もデータを探す方法が思いつかず、データに上限がある場合にこの方法が実現できるのです.
クリックイベントを追加
描き終わったら、クリックイベントができるかどうか、具体的にはクリックイベントの方法に戻ります.
これで、結合データ部分が完了します.
補足説明
コントロールアニメーションについて
元のコントロールでは、表示と非表示の両方のアニメーションが実際に親コントロールのサイズを変更するため、ここでの非表示はVisibilityのパラメータを変更することによって行われません.
初期非表示の問題について
上記の状況により、コントロールを初期非表示にするには、親コントロールの高さを0に設定するだけでよく、非ストレッチの展開を使用する場合は、親コントロールの幅も0に設定する必要があります.
コントロール以外の場所をクリックしてカレンダーコントロールを隠す実装について
開発時間の関係上、このクリックはコントロールにカプセル化されていませんが、実際にクリック以外の場所はonTouchメソッドで現在クリックしているviewがカレンダーコントロールではないということです.
CompactCalendarViewの作者に感謝します.
このコントロールはGitHub上のカレンダー項目に基づいて、高度にカスタマイズされた修正版です.そのため、元の項目の住所を添付します.https://github.com/SundeepK/CompactCalendarView
概要
CompactCalendarViewは、カレンダーのデフォルト当日および他の日付を選択する表示、スライドイベント、クリックイベントなどの機能を実現し、非常に完全なオープンソースプロジェクトです.--[プロジェクトアドレス]
しかし、開発の必要性に介在して、まだ多くの機能が実現されていないので、ここで詳細なカスタマイズの需要を説明して、あなたを助けることができることを望んでいます.
文章コントロールの原型はCompactCalendarViewを使用し、多くの使いやすい機能を拡張しています.元のコントロール機能の使用方法は、Githubを参照してください.
カスタムヘッダの実装
CompactCalendarView:プロジェクトを開くとパッケージ化されたviewであることがわかります具体的な操作はCompactCalendarControllerクラスに渡されました
主な方法は次のとおりです.
void drawMonth(Canvas canvas, Calendar monthToDrawCalender, int offset)
このメソッドの最初のパラメータは言うまでもなく、分からない場合はカスタムviewのOnDrawメソッドをご自身でご理解ください
2番目のパラメータは、特定の日付を判断するために使用されます.
3番目のパラメータはオフセット量を表すために使用されます(このオフセット量はスライドイベントのオフセット量を指します).
主なロジック:
for (int dayColumn = 0, dayRow = 0; dayColumn <= 6; dayRow++) {
if (dayRow == 7) {
dayRow = 0;
if (dayColumn <= 6) {
dayColumn++;
}
}
if (dayColumn == dayColumnNames.length) {
break;
}
float xPosition = widthPerDay * dayColumn + paddingWidth + paddingLeft + accumulatedScrollOffset.x + offset - paddingRight;
float yPosition = dayRow * heightPerDay + paddingHeight + headHeight;
if (xPosition >= growFactor && (isAnimatingWithExpose || animationStatus == ANIMATE_INDICATORS) || yPosition >= growFactor) {
continue;
}
if (dayRow == 0) {
if (shouldDrawDaysHeader) {
dayPaint.setColor(calenderTextColor);
dayPaint.setTypeface(Typeface.DEFAULT_BOLD);
dayPaint.setStyle(Paint.Style.FILL);
dayPaint.setColor(calenderTextColor);
canvas.drawText(dayColumnNames[dayColumn], xPosition, paddingHeight, dayPaint);
dayPaint.setTypeface(Typeface.DEFAULT);
}
}
上記のコードから明らかなように、これは7行7列のマトリクスを描き、最初の行は曜日を表示します.
スペースにヘッドビューを追加するにはここで文章を書かなければなりません
ヘッドビューの追加
void drawHead(Canvas canvas, Calendar yearToMonthCalender, int offset) {
int year = yearToMonthCalender.get(Calendar.YEAR); //
int month = yearToMonthCalender.get(Calendar.MONTH) + 1; // ,0 1
dayRect.setColor(Color.argb(255, 66, 66, 66));
dayRect.setStyle(Paint.Style.FILL);
dayRect.setTextSize(textSize + 12);
String text = year + " " + month + " ";
float textWidth = dayRect.measureText(text);
// offset ( )
if (width * -monthsScrolledSoFar == offset) {
Rect lastRect = new Rect((int)(widthPerDay * 2 + paddingWidth + paddingLeft - paddingRight - lastMonthIcon.getWidth())
,textSize/2
,(int)(widthPerDay * 2 + paddingWidth + paddingLeft - paddingRight)
, textSize+paddingHeight/2);
Rect nextRect = new Rect((int)(widthPerDay * 4 + paddingWidth + paddingLeft - paddingRight)
,textSize/2
,(int)(widthPerDay * 4 + paddingWidth + paddingLeft - paddingRight+nextMonthIcon.getWidth())
,textSize+paddingHeight/2);
canvas.drawText(text, widthPerDay * 7 / 2 - textWidth / 2, paddingHeight, dayRect);
canvas.drawBitmap(nextMonthIcon, null , nextRect, null);
canvas.drawBitmap(lastMonthIcon, null, lastRect, null);
}
}
ここでは簡単に頭を描き、現実の年月のテキストと月を切り替えるためのボタンを2つ描き、drawMonthメソッドにこのメソッドを配置し、頭の位置を予約して具体的なコードを以下のように変更します.
void drawMonth(Canvas canvas, Calendar monthToDrawCalender, int offset) {
...
drawHead(canvas, monthToDrawCalender, offset);//
...
// headHeight
for (int dayColumn = 0, dayRow = 0; dayColumn <= 6; dayRow++) {
if (dayRow == 7) {
dayRow = 0;
if (dayColumn <= 6) {
dayColumn++;
}
}
if (dayColumn == dayColumnNames.length) {
break;
}
float xPosition = widthPerDay * dayColumn + paddingWidth + paddingLeft + accumulatedScrollOffset.x + offset - paddingRight;
float yPosition = dayRow * heightPerDay + paddingHeight + headHeight;
if (xPosition >= growFactor && (isAnimatingWithExpose || animationStatus == ANIMATE_INDICATORS) || yPosition >= growFactor) {
continue;
}
if (dayRow == 0) {
if (shouldDrawDaysHeader) {
dayPaint.setColor(calenderTextColor);
dayPaint.setTypeface(Typeface.DEFAULT_BOLD);
dayPaint.setStyle(Paint.Style.FILL);
dayPaint.setColor(calenderTextColor);
canvas.drawText(dayColumnNames[dayColumn], xPosition, paddingHeight + headHeight, dayPaint);
dayPaint.setTypeface(Typeface.DEFAULT);
}
}
これにより、私たちの頭部がビューに表示され、このコントロールは全体的に1つの頭部の距離を下に移動することに相当し、すべてのクリックイベントが錯乱するので、私たちの対応するクリックイベントを追加するついでに、既存のクリックイベントを校正します.
ヘッドクリックイベントの追加
まず自分で追加した頭部のクリックイベントを書いて、コードは以下の通りです.
boolean onIconTouch(MotionEvent event){
int x = Math.round((paddingLeft + event.getX() - paddingWidth - paddingRight) / widthPerDay);
int y = Math.round((event.getY()));
if (x ==2
&& y < headHeight+paddingHeight
&& y > 0) {
scrollPreviousMonth();
return true;
} else if (x == 4
&& y < headHeight+paddingHeight
&& y > 0) {
scrollNextMonth();
return true;
}
return false;
}
私は左右の2つのボタンを3列目と5列目の位置に配置しました.自分のニーズに合わなければ、自分で修正することができます.その後、私たちのクリックイベントを既存のクリックイベントに追加し、クリックイベントの乱れ問題を修正します.
void onSingleTapUp(MotionEvent e) {
// Don't handle single tap when calendar is scrolling and is not stationary
if (isScrolling()) {
return;
}
//
if (onIconTouch(e)){
return;
}
int dayColumn = Math.round((paddingLeft + e.getX() - paddingWidth - paddingRight) / widthPerDay);
//
int dayRow = Math.round((e.getY() - paddingHeight - headHeight) / heightPerDay);
ここまでヘッダの追加が完了しました.
カレンダコントロールにデータを追加し、データに基づいて表示スタイルを変更します.
私たちはこのような需要があると仮定して、私たちは毎日のデータをローカルに保存して、その日ローカルにデータがあればクリックして相応のデータを取り出すことができて、しかもオプションの日付は黒で、オプションの日は灰色です.このようなニーズは、カレンダーコントロールとデータをバインドする必要があります.では、まずデータから始めましょう.
コントロールにデータを追加するには、次の手順に従います.
List<Calendar> list;//
//
void setDates(List<DateEntry> dates,Context context){
this.list = new ArrayList<>();
if (dates.size() == 0 || dates.isEmpty()){
dates = null ;
}else {
for (int i = 0; i < dates.size() ; i++) {
Calendar c = Calendar.getInstance(timeZone,locale);
c.setTime(new Date(dates.get(i).getTime()));
this.list.add(c);
}
}
init(context);
}
この方法をCompactCalendarViewに公開しました
public void setDates(List<DateEntry> list , Context context){
compactCalendarController.setDates(list,context);
}
これにより、データが入力されると、関連する操作が可能になります.
データに基づいてカレンダ関連の表示を制御
それとも描画方法に戻るか、
// , ,
int day = ((dayRow - 1) * 7 + dayColumn + 1) - firstDayOfMonth;
int defaultCalenderTextColorToUse = calenderTextColor;
if (currentCalender.get(Calendar.DAY_OF_MONTH) == day && isSameMonthAsCurrentCalendar && !isAnimatingWithExpose) {
drawDayCircleIndicator(currentSelectedDayIndicatorStyle, canvas, xPosition, yPosition, currentSelectedDayBackgroundColor);
defaultCalenderTextColorToUse = Color.WHITE;
} else if (isSameYearAsToday && isSameMonthAsToday && todayDayOfMonth == day && !isAnimatingWithExpose) {
drawDayCircleIndicator(currentDayIndicatorStyle, canvas, xPosition, yPosition, currentDayBackgroundColor);
defaultCalenderTextColorToUse = currentDayTextColor;
}
ここで筆者は現在表示されている月のみについて操作するので、ここでelse ifコードを追加すると以下のようになります.
} else if (list == null || list.isEmpty()) {
// ,
defaultCalenderTextColorToUse = Color.argb(255,189,189,189);
} else {
// , ,
for (int i = 0; i < list.size(); i++) {
Calendar c = list.get(i);
if (c.get(Calendar.MONTH) == monthToDrawCalender.get(Calendar.MONTH)
&& c.get(Calendar.DAY_OF_MONTH) == day) {
defaultCalenderTextColorToUse = calenderTextColor;
break;
} else {
defaultCalenderTextColorToUse = Color.argb(255,189,189,189);
}
}
}
ここではフォントの色を変えたと判断するだけで、集合を巡る方法で対応するデータを探すのは理想的ではありませんが、仕方なく筆者もデータを探す方法が思いつかず、データに上限がある場合にこの方法が実現できるのです.
クリックイベントを追加
描き終わったら、クリックイベントができるかどうか、具体的にはクリックイベントの方法に戻ります.
//
boolean canSelect = false;
//
if (list == null || list.isEmpty()) {
canSelect = false;
} else {
for (int i = 0; i < list.size(); i++) {
Calendar c = list.get(i);
if (c.get(Calendar.MONTH) == calendarWithFirstDayOfMonth.get(Calendar.MONTH)
&& (c.get(Calendar.DAY_OF_MONTH)-1) == dayOfMonth) {
canSelect = true;
break;
}
}
}
//
if (canSelect) {
calendarWithFirstDayOfMonth.add(Calendar.DATE, dayOfMonth);
currentCalender.setTimeInMillis(calendarWithFirstDayOfMonth.getTimeInMillis());
performOnDayClickCallback(currentCalender.getTime());
}
これで、結合データ部分が完了します.
補足説明
コントロールアニメーションについて
元のコントロールでは、表示と非表示の両方のアニメーションが実際に親コントロールのサイズを変更するため、ここでの非表示はVisibilityのパラメータを変更することによって行われません.
初期非表示の問題について
上記の状況により、コントロールを初期非表示にするには、親コントロールの高さを0に設定するだけでよく、非ストレッチの展開を使用する場合は、親コントロールの幅も0に設定する必要があります.
コントロール以外の場所をクリックしてカレンダーコントロールを隠す実装について
開発時間の関係上、このクリックはコントロールにカプセル化されていませんが、実際にクリック以外の場所はonTouchメソッドで現在クリックしているviewがカレンダーコントロールではないということです.
public boolean onTouch(View v, MotionEvent event) {
if (v instanceof CompactCalendarView) {
} else {
if (shouldShow) {
if (!compactCalendarView.isAnimating()) {
compactCalendarView.hideCalendar();
shouldShow = false;
}
}
}
return false;
}
CompactCalendarViewの作者に感謝します.