This commit is contained in:
JUNGGWAN KIM 2024-12-20 16:18:45 +09:00
parent a1162f2f4c
commit 41824758a7
18 changed files with 847 additions and 294 deletions

View File

@ -0,0 +1,48 @@
package com.example.calrendarview.Adapter
import android.os.Build
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.FrameLayout
import android.widget.LinearLayout.LayoutParams
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.recyclerview.widget.RecyclerView
import com.example.calrendarview.MonthLayout
import com.example.calrendarview.model.CalendarFactory
import com.example.calrendarview.model.CalendarPod
import java.time.LocalDate
@RequiresApi(Build.VERSION_CODES.O)
class PagerAdapter(
private val pods: ArrayList<CalendarPod>,
private val idLayout: Int,
private val idTextViewNumOfDay: Int
): RecyclerView.Adapter<PagerAdapter.ViewHolder>() {
inner class ViewHolder(val view: View): RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): PagerAdapter.ViewHolder {
val container = ConstraintLayout(parent.context).apply {
this.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
}
return ViewHolder(container)
}
override fun onBindViewHolder(holder: PagerAdapter.ViewHolder, position: Int) {
val container = holder.view as ViewGroup
val a = MonthLayout(holder.view.context).apply {
this.layoutParams = ConstraintLayout.LayoutParams(LayoutParams.MATCH_PARENT, ConstraintLayout.LayoutParams.MATCH_PARENT)
this.idLayout = this@PagerAdapter.idLayout
this.idTextViewNumOfDay = this@PagerAdapter.idTextViewNumOfDay
this.listOfBean = CalendarFactory().getBeansOfMonth(pods[position])
this.targetYear = pods[position].year
this.targetMonth = pods[position].month
}
container.removeAllViews()
container.addView(a)
Log.d("holder >>>>>","holder ${holder.view.height}, ${holder.view.width}")
}
override fun getItemCount(): Int = pods.size
}

View File

@ -0,0 +1,70 @@
package com.example.calrendarview
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.children
abstract class BaseCustomLayout : ConstraintLayout {
constructor(context: Context) : super(context){applyAttrs(context,null)}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){applyAttrs(context,attrs)}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
){applyAttrs(context,attrs)}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {applyAttrs(context,attrs)}
protected val tag = this:: class.simpleName
// 하루가 표시될 layout id
var idLayout : Int = -1
// 날짜(num)가 표시될 TextView
var textViewNumOfDay : TextView? = null
// 날짜(num)가 표시될 TextView 의 id
var idTextViewNumOfDay : Int = -1
set(value) {
field = value
Log.e(tag, "idTextViewNumOfDay $field")
}
private fun applyAttrs(context: Context?, attrs: AttributeSet?) {
context?.let {
onTypedArray(it, it.obtainStyledAttributes(attrs, R.styleable.BaseCustomLayout))
}
}
open fun onTypedArray(context: Context, typedArray : TypedArray) {
Log.e(tag, "context (${context})")
idLayout = typedArray.getResourceId(R.styleable.BaseCustomLayout_item_layout, R.layout.item_day).also {
Log.e(tag, "idLayout default (${R.layout.item_day})")
Log.e(tag, "idLayout (${idLayout}) Id >>>> ${it}")
}
idTextViewNumOfDay = typedArray.getResourceId(R.styleable.BaseCustomLayout_numOfDayId, R.id.day_num).also {
Log.e(tag, "idTextViewNumOfDay default (${R.id.day_num})")
Log.e(tag, "idTextViewNumOfDay (${idTextViewNumOfDay}) Id >>>> ${it}")
}
initLayout(context)
}
open fun initLayout(context: Context?) {
// createdLayout(LayoutInflater.from(context).inflate(idLayout, this, true))
}
open fun createdLayout(view : View) {
Log.e(tag,"Created view is $view")
}
}

View File

@ -1,54 +0,0 @@
package com.example.calrendarview
import android.content.Context
import android.content.res.TypedArray
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.constraintlayout.widget.ConstraintLayout
abstract class BaseCustomViews : ConstraintLayout {
protected val TAG = this:: class.simpleName
constructor(context: Context) : super(context){appyAttrs(context,null)}
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs){appyAttrs(context,attrs)}
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
){appyAttrs(context,attrs)}
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes) {appyAttrs(context,attrs)}
var layouId : Int = -1
open fun appyAttrs(context: Context?, attrs: AttributeSet?) {
context?.let {
onTypedArray(it,it.obtainStyledAttributes(attrs, R.styleable.BaseCustomViews))
}
}
open fun onTypedArray(context: Context, typedArray : TypedArray) {
layouId = typedArray.getResourceId(R.styleable.BaseCustomViews_item_layout,R.layout.item_day)
initLayout(context)
}
fun initLayout(context: Context?) {
createdLayout(LayoutInflater.from(context).inflate(layouId, this, true))
}
open fun createdLayout(view : View) {
Log.e(this::class.simpleName,"view si $view")
}
// override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
// if (changed) {
//
// }
// }
}

View File

@ -0,0 +1,77 @@
package com.example.calrendarview
import android.annotation.SuppressLint
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.viewpager2.widget.ViewPager2
import com.example.calrendarview.Adapter.PagerAdapter
import com.example.calrendarview.model.CalendarBean
import com.example.calrendarview.model.CalendarFactory
import com.example.calrendarview.model.CalendarPod
import java.time.LocalDate
@RequiresApi(Build.VERSION_CODES.O)
class CalendarLayout: BaseCustomLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes) {
this.attrs = attrs
this.defStyleAttr = defStyleAttr
this.defStyleRes = defStyleRes
}
var attrs: AttributeSet? = null
var defStyleAttr: Int? = null
var defStyleRes: Int? = null
private lateinit var pager: ViewPager2
private var pods: ArrayList<CalendarPod> = arrayListOf()
// Constraint Layout
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// Create a pager
pager = createPager()
// Attach a pager
this.removeAllViews()
this.addView(pager)
// Set pager's adapter
// Set data
setData(LocalDate.now())
pager.adapter = PagerAdapter(pods, idLayout, idTextViewNumOfDay)
pager.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
Log.d(tag, "pager width = ${pager.measuredWidth}")
Log.d(tag, "pager height = ${pager.measuredHeight}")
}
override fun requestLayout() {
super.requestLayout()
Log.e(tag, "did requestLayout")
}
// fun
fun createPager(): ViewPager2 = ViewPager2(context).apply {
this.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT)
orientation = ViewPager2.ORIENTATION_HORIZONTAL
}
private fun setData(date: LocalDate) {
pods.add(CalendarPod(2024, 11))
pods.add(CalendarPod(LocalDate.now()))
pods.add(CalendarPod(2025, 1))
}
}

View File

@ -0,0 +1,76 @@
package com.example.calrendarview
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.view.children
import com.example.calrendarview.model.DayInfo
class DayLayout : BaseCustomLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
// data
private var infoDay: DayInfo? = null
// Constraint Layout -----------------------------------------
// size
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
}
// location
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
}
override fun onDraw(canvas: Canvas) {
super.draw(canvas)
}
override fun requestLayout() {
super.requestLayout()
onBindInfo()
}
// -----------------------------------------------------------
// BaseCustomLayout ------------------------------------------
override fun initLayout(context: Context?) {
super.initLayout(context)
val view = LayoutInflater.from(context).inflate(idLayout, this, true)
(view as? ViewGroup)?.let {
it.children.forEach { Log.e(tag,"child is ${it}") }
}
textViewNumOfDay = findViewById<TextView>(idTextViewNumOfDay).also {
Log.e(tag, "textViewNumOfDay $textViewNumOfDay >>> ${it}")
}
}
// -----------------------------------------------------------
private fun onBindInfo() {
textViewNumOfDay?.text = infoDay?.getNumOfDay()?.toString() ?: "TEST"
Log.e(tag, "textViewNumOfDay >>>> 4 ${textViewNumOfDay}")
Log.e(tag, "textViewNumOfDay?.text >>>> 4 ${textViewNumOfDay?.text}")
}
}

View File

@ -1,97 +0,0 @@
package com.example.calrendarview
import android.content.Context
import android.content.res.TypedArray
import android.graphics.Canvas
import android.graphics.Color
import android.util.AttributeSet
import android.util.Log
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.view.children
import com.example.calrendarview.model.DayInfo
class DayView : BaseCustomViews {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
constructor(
context: Context,
attrs: AttributeSet?,
defStyleAttr: Int,
defStyleRes: Int
) : super(context, attrs, defStyleAttr, defStyleRes)
var dayInfo: DayInfo? = null
set(value) {
field = value
displayDayNumber()
}
var numOfDayView : TextView? = null
var numberOfday : Int = -1
set(value) {
Log.e(TAG, "numOfDayView 2 (${R.id.day_num}) Id >>>> ${value}")
field = value
numOfDayView = findViewById<TextView>(field)
Log.e(TAG, "numOfDayView >>>> 3 ${numOfDayView}")
}
// override fun appyAttrs(context: Context?, attrs: AttributeSet?) {
// context?.let {
// Log.e(TAG, "numOfDayView >>>> ${numOfDayView}")
// var typedArray = it.obtainStyledAttributes(attrs, R.styleable.BaseCustomViews)
// layouId = typedArray.getResourceId(R.styleable.BaseCustomViews_item_layout,R.layout.item_day).apply {
// Log.e(TAG, "layouId 0 (${R.layout.item_day} Id >>>> ${this}")
// }
// initLayout(context)
//
// }
// }
override fun onTypedArray(context: Context, typedArray: TypedArray) {
super.onTypedArray(context, typedArray)
numberOfday = typedArray.getResourceId(R.styleable.BaseCustomViews_numOfDayId, R.id.day_num).apply {
Log.e(TAG, "numOfDayView 1 (${R.id.day_num}) Id >>>> ${this}")
}
displayDayNumber()
}
override fun createdLayout(view: View) {
super.createdLayout(view)
(view as? ViewGroup)?.let {
it.children.forEach { Log.e(TAG,"child is ${it}") }
}
}
fun displayDayNumber() {
numOfDayView?.text = dayInfo?.getNumOfDay()?.toString() ?: "TEST"
Log.e(TAG, "numOfDayView?.text >>>> 4 ${numOfDayView?.text}")
}
fun displayDayOfWeek() {
//todo 오늘의 요일을 표시?
}
fun isToday() : Boolean {
return false
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
Log.e(TAG,"View >>> ${this}")
}
// override fun draw(canvas: Canvas) {
// super.draw(canvas)
// canvas.drawColor(Color.CYAN)
// }
}

View File

@ -0,0 +1,285 @@
package com.example.calrendarview
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.util.TypedValue
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.children
import androidx.core.view.contains
import androidx.viewpager2.widget.ViewPager2
import androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL
import androidx.viewpager2.widget.ViewPager2.Orientation
import com.example.calrendarview.Adapter.PagerAdapter
import com.example.calrendarview.model.CalendarBean
import com.example.calrendarview.model.CalendarFactory
import java.time.LocalDate
@RequiresApi(Build.VERSION_CODES.O)
class MonthLayout: BaseCustomLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
private var isInitializing: Boolean = false
private var listDayView: ArrayList<ViewGroup> = arrayListOf()
private val numberOfRow : Int = 7
private val numberOfWeek : Int = 6
var listOfBean: Array<CalendarBean> = arrayOf()
private var listHeaderView: ArrayList<View> = arrayListOf()
private var isShowingHeader: Boolean = true
private var heightOfHeader: Int = 50
var targetYear: Int = 0
var targetMonth: Int = 0
private var titleView: View? = null
private var heightOfTitle: Int = 100
private var header: LinearLayout? = null
// Constraint Layout -----------------------------------------------------
override fun onAttachedToWindow() {
super.onAttachedToWindow()
this.removeAllViews()
// Make data
// setData(LocalDate.now())
Log.d(tag, "listOfBean.size ${listOfBean.size}")
// Create view for title
createTitle()
// Create view for day of week
createHeader()
Log.e(tag, "listHeaderView.size ${listHeaderView.size}")
// Create day views and add.
Log.e(tag, "idLayout ${idLayout}")
createdDayView()
Log.d(tag, "listDayView.size ${listDayView.size}")
// Bind day views with data
if (listDayView.isNotEmpty()) {
for (i in 0 until listDayView.size) {
bindWidthData(listDayView[i], listOfBean[i])
}
}
}
// size
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
isInitializing = true
val selfW = MeasureSpec.getSize(widthMeasureSpec)
val selfH = MeasureSpec.getSize(heightMeasureSpec)
Log.d(tag, "selfW, selfH => ${selfW} ,${selfH}")
// Set size of view for day of week
Log.d(tag, "header measuredW, measuredH => ${header?.measuredWidth} ,${header?.measuredHeight}")
listHeaderView.forEachIndexed { _, view ->
// view.layoutParams = LayoutParams(selfW/numberOfRow, heightOfHeader)
Log.d(tag, "header view child measuredW, measuredH => ${view.measuredWidth} ,${view.measuredHeight}")
}
// Set size of day views
listDayView.forEachIndexed { _, view ->
// view.layoutParams = LayoutParams(selfW/numberOfRow, (selfH - (if (isShowingHeader) heightOfHeader else 0) - heightOfTitle)/numberOfWeek)
val headerH = if (isShowingHeader) heightOfHeader else 0
val titleH = titleView?.measuredHeight ?: 0
val w = selfW/numberOfRow
val h = (selfH - titleH - headerH)/numberOfWeek
view.measure(w, h)
Log.d(tag, "day view measuredW, measuredH => ${view.measuredWidth} ,${view.measuredHeight}")
}
// title view
Log.d(tag, "title view measuredW, measuredH => ${titleView?.measuredWidth} ,${titleView?.measuredHeight}")
isInitializing = false
}
// location
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
// Locate Title view
// locatedTitleView()
// Locate view for day of week
locatedHeaderView(listHeaderView)
// Locate day views
locatedDayView(listDayView)
requestLayout()
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
}
override fun requestLayout() {
if (isInitializing) {
return
}
super.requestLayout()
Log.e(tag, "did requestLayout")
}
// fun
private fun setData(date: LocalDate) {
listOfBean = arrayOf()
listOfBean = CalendarFactory().getBeansOfThisMonth()
targetYear = LocalDate.now().year
targetMonth = LocalDate.now().monthValue
}
private fun createdDayView() {
Log.d(tag, "on createdDayView")
isInitializing = true
// create and add to listDayView
listDayView.clear()
for (i in 0 until numberOfRow * numberOfWeek) {
listDayView.add((LayoutInflater.from(context).inflate(idLayout, this, false) as ViewGroup))
}
// add children
listDayView.forEach {
this.addView(it)
}
isInitializing = false
}
private fun bindWidthData(view: ViewGroup, bean: CalendarBean) {
textViewNumOfDay = view.findViewById<TextView>(idTextViewNumOfDay).apply {
this.text = bean.getNumOfDay().toString()
if (targetMonth != bean.getMonth()) {
this.setTextColor(Color.parseColor("#cccccc"))
view.children.forEach {c ->
if (c != this) {
c.visibility = GONE
}
}
}
}
}
fun createTitle() {
if (titleView != null) {
titleView = null
}
titleView = TextView(context).apply {
this.id
this.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, heightOfTitle)
this.text = "$targetYear $targetMonth"
this.textSize = 18f
this.gravity = Gravity.CENTER
this.setBackgroundColor(Color.parseColor("#99ffff"))
}
this.addView(titleView)
}
fun createHeader() {
// if(header == null) {
header = LinearLayout(context).apply {
this.layoutParams = LayoutParams(LayoutParams.MATCH_PARENT, heightOfHeader)
this.orientation = ORIENTATION_HORIZONTAL
}
this.addView(header)
// }
// 주간 요일 표시
for (i in 0 until numberOfRow) {
Log.d(this@MonthLayout.tag, "getDayOfWeek ${listOfBean[i].getDayOfWeek()}")
TextView(context).apply {
this.layoutParams = LinearLayout.LayoutParams(0, heightOfHeader, 1f)
this.text = listOfBean[i].getDayOfWeek()
this.textSize = 8f
this.gravity = Gravity.CENTER
this.setBackgroundColor(Color.parseColor("#eeeeee"))
listHeaderView.add(this)
}.run {
header!!.addView(this)
}
}
}
fun locatedTitleView() {
isInitializing = true
titleView?.let {
it.layout(
this.x.toInt(),
this.y.toInt(),
this.x.toInt() + it.measuredWidth,
this.y.toInt() + it.measuredHeight
)
Log.d(tag, "locatedTitleView s = ${this.x.toInt()}")
Log.d(tag, "locatedTitleView t = ${this.y.toInt()}")
Log.d(tag, "locatedTitleView e = ${this.x.toInt() + it.measuredWidth}")
Log.d(tag, "locatedTitleView b = ${this.y.toInt() + it.measuredHeight}")
}
isInitializing = false
}
fun locatedHeaderView(list: ArrayList<View>) {
var mutableX = this.x.toInt()
val mutableY = this.y.toInt()
val headerH = if (isShowingHeader) heightOfHeader else 0
isInitializing = true
header?.let{
it.layout(
mutableX,
mutableY + (titleView?.measuredHeight ?: 0),
mutableX + it.measuredWidth,
mutableY + (titleView?.measuredHeight ?: 0) + it.measuredHeight
)
}
list.forEach {
if (header?.contains(it) ?: false &&
it.visibility != GONE) {
Log.d(tag, "Header s, t => ${header!!.x}, ${header!!.y}")
Log.d(tag, "Header e, b => ${header!!.x + header!!.measuredWidth}, ${header!!.y + header!!.measuredHeight}")
Log.d(tag, "locatedHeaderView s, t => ${it.x}, ${it.y}")
Log.d(tag, "locatedHeaderView e, b => ${it.x + it.measuredWidth}, ${it.y + it.measuredHeight}")
}
}
isInitializing = false
}
private fun locatedDayView(list: ArrayList<ViewGroup>) {
var mutableX = this.x.toInt()
val headerH = if (isShowingHeader) heightOfHeader else 0
val titleH = titleView?.measuredHeight ?: 0
var mutableY = this.y.toInt() + headerH + titleH
Log.e(tag, "locatedDayView mutableX, mutableY ${this.x.toInt()}, ${this.y.toInt()}")
val w = this.measuredWidth/numberOfRow
val h = (this.measuredHeight - titleH - headerH)/numberOfWeek
isInitializing = true
list.forEachIndexed { i, it ->
if (this.contains(it) &&
it.visibility != GONE) {
if (i % numberOfRow == 0 &&
i != 0) {
mutableX = this.x.toInt()
mutableY += h
}
Log.e(tag, "locatedDayView x y ${mutableX}, ${mutableY + headerH + titleH}")
Log.e(tag, "locatedDayView r e ${mutableX + w}, ${mutableY + h}")
it.layout(
mutableX,
mutableY,
mutableX + w,
mutableY + h
)
mutableX += w
Log.e(tag, "locatedDayView x y ${it.x}, ${it.y}")
Log.e(tag, "locatedDayView r e ${it.x + it.measuredWidth}, ${it.y + it.measuredHeight}")
}
}
isInitializing = false
}
}

View File

@ -1,111 +0,0 @@
package com.example.calrendarview
import android.content.Context
import android.content.res.TypedArray
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.core.view.size
import com.example.calrendarview.model.CalendarFactory
import com.example.calrendarview.model.DayInfo
@RequiresApi(Build.VERSION_CODES.O)
class MonthView : BaseCustomViews {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
override fun appyAttrs(context: Context?, attrs: AttributeSet?) {
super.appyAttrs(context, attrs)
}
var numberOfRow : Int = 7
set(value) {
field = value
}
var dayInfo: DayInfo? = null
set(value) {
field = value
displayDayNumber()
}
var numberOfday : Int = -1
set(value) {
field = value
numOfDayView = findViewById<TextView>(field)
}
var itemLayout : Int = -1
set(value) {
field = value
}
var numOfDayView : TextView? = null
var mWidth: Int? = null
var mHeight: Int? = null
override fun onTypedArray(context: Context, typedArray: TypedArray) {
super.onTypedArray(context, typedArray)
numberOfday = typedArray.getResourceId(R.styleable.BaseCustomViews_numOfDayId, R.id.day_num)
itemLayout = typedArray.getResourceId(R.styleable.BaseCustomViews_item_layout, R.id.day_num)
displayDayNumber()
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
Log.i("MonthView >>> ","onLayout")
initChildViews()
}
fun initChildViews(): Array<View?> {
//todo : 7 * numberOfRow 의 차일드 뷰를 만든다.
val infos = CalendarFactory().getBeansOfThisWeek()
val childrens = Array<View?>(numberOfRow) {i ->
val dayView = LayoutInflater.from(context).inflate(layouId, this, false)
val p = ViewGroup.LayoutParams(100, 100)
Log.i("MonthView >>> ","numberOfRow ${numberOfRow}")
dayView?.let {
it.layoutParams = p
Log.i("MonthView >>> ","dayView.width ${dayView.width}")
numOfDayView?.text = infos[i].getNumOfDay().toString()
addView(it)
}
return@Array dayView
}
Log.i("MonthView initChildViews >>> ","childrens count ${childrens.size}")
Log.i("MonthView initChildViews >>> ","mWidth ${width}")
Log.i("MonthView initChildViews >>> ","mHeight ${height}")
return childrens
}
fun displayDayNumber() {
numOfDayView?.text = dayInfo?.getNumOfDay()?.toString() ?: "TEST"
Log.e(TAG, "numOfDayView?.text >>>> 4 ${numOfDayView?.text}")
}
fun displyMonthOfNumber() {
//todo :월 표시
}
fun displayWeekHeader() {
//todo 주간 요일 표시
}
fun displayYear(){
//todo 년도 표시
}
fun setData(days : Collection<DayInfo>) {
//todo 최대 7*6의 데이터를 받는다.
}
}

View File

@ -0,0 +1,188 @@
package com.example.calrendarview
import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.os.Build
import android.util.AttributeSet
import android.util.Log
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.constraintlayout.widget.ConstraintLayout
import androidx.core.view.children
import androidx.core.view.contains
import androidx.core.view.forEach
import androidx.core.view.get
import com.example.calrendarview.model.CalendarBean
import com.example.calrendarview.model.CalendarFactory
import com.example.calrendarview.model.DayInfo
import java.time.LocalDate
@RequiresApi(Build.VERSION_CODES.O)
class WeekLayout : BaseCustomLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int, defStyleRes: Int) : super(context, attrs, defStyleAttr, defStyleRes)
// view
private val numberOfRow : Int = 7
private var listDayView: ArrayList<View> = arrayListOf()
private var listHeaderView: ArrayList<View> = arrayListOf()
private var heightOfHeader: Int = 50
private var isShowingHeader: Boolean = true
// data
private var listOfBean: Array<CalendarBean> = arrayOf()
// state, flag
private var isInitializing: Boolean = false
// Constraint Layout -----------------------------------------------------
override fun onAttachedToWindow() {
super.onAttachedToWindow()
// Create day views and add.
createdDayView()
// Bind day views with data
setData(LocalDate.now())
if (listDayView.isNotEmpty()) {
for (i in 0 until numberOfRow) {
bindWidthData(listDayView[i], listOfBean[i])
}
}
// Create view for day of week
createHeader()
}
// size
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec)
isInitializing = true
val selfW = MeasureSpec.getSize(widthMeasureSpec)
val selfH = MeasureSpec.getSize(heightMeasureSpec)
// Set size of day views
listDayView.forEachIndexed { _, view ->
Log.e(tag, "idLayout ${idLayout}")
view.layoutParams = LayoutParams(selfW/numberOfRow, selfH)
}
// Set size of view for day of week
Log.e(tag, "listHeaderView.size ${listHeaderView.size}")
listHeaderView.forEachIndexed { _, view ->
view.layoutParams = LayoutParams(selfW/numberOfRow, if (isShowingHeader) heightOfHeader else 0)
}
isInitializing = false
}
// location
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
super.onLayout(changed, left, top, right, bottom)
// Locate view for day of week
locatedHeaderView(listHeaderView)
// Locate day views
locatedDayView(listDayView)
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
}
override fun requestLayout() {
if (isInitializing) {
return
}
super.requestLayout()
Log.e(tag, "on requestLayout")
}
// -------------------------------------------------------------------------
// BaseCustomLayout ------------------------------------------
// override fun initLayout(context: Context?) {
// super.initLayout(context)
// }
// -----------------------------------------------------------
private fun createdDayView() {
Log.e(tag, "on createdDayView")
isInitializing = true
// create and add to listDayView
listDayView.clear()
for (i in 0 until numberOfRow) {
Log.e(tag, "idLayout ${idLayout}")
listDayView.add(LayoutInflater.from(context).inflate(idLayout, this, false))
}
Log.e(tag, "listDayView.size ${listDayView.size}")
// add children
listDayView.forEach {
this.addView(it)
}
isInitializing = false
}
private fun locatedDayView(list: ArrayList<View>) {
var mutableX = this.x.toInt()
val mutableY = this.y.toInt()
val headerH = if (isShowingHeader) heightOfHeader else 0
isInitializing = true
list.forEach {
if (this.contains(it) &&
it.visibility != GONE) {
it.layout(mutableX, mutableY + headerH, mutableX + it.measuredWidth, mutableY + it.measuredHeight + headerH)
mutableX += it.measuredWidth
Log.e(tag, "locatedDayView x y ${mutableX}, ${ this.y}")
}
}
isInitializing = false
requestLayout()
}
private fun setData(date: LocalDate) {
listOfBean = arrayOf()
listOfBean = CalendarFactory().getBeansOfWeek(date)
}
private fun bindWidthData(view: View, bean: CalendarBean) {
textViewNumOfDay = view.findViewById<TextView>(idTextViewNumOfDay).apply {
this.text = bean.getNumOfDay().toString()
}
}
fun createHeader() {
//todo 주간 요일 표시
for (i in 0 until numberOfRow) {
Log.e(tag, "getDayOfWeek ${listOfBean[i].getDayOfWeek()}")
TextView(context).apply {
this.text = listOfBean[i].getDayOfWeek()
this.textSize = 8f
this.width = listDayView[i].width
this.height = 50
this.gravity = Gravity.CENTER
this.setBackgroundColor(Color.parseColor("#eeeeee"))
listHeaderView.add(this)
this@WeekLayout.addView(this)
}
}
}
fun locatedHeaderView(list: ArrayList<View>) {
var mutableX = this.x.toInt()
val mutableY = this.y.toInt()
val headerH = if (isShowingHeader) heightOfHeader else 0
isInitializing = true
list.forEach {
if (this.contains(it) &&
it.visibility != GONE) {
it.layout(mutableX, mutableY, mutableX + it.measuredWidth, mutableY + headerH)
mutableX += it.measuredWidth
Log.e(tag, "locatedHeaderView x y ${mutableX}, ${ this.y}")
}
}
isInitializing = false
requestLayout()
}
}

View File

@ -1,6 +1,7 @@
package com.example.calrendarview.model
import android.os.Build
import android.util.Log
import androidx.annotation.RequiresApi
import java.time.DayOfWeek
import java.time.LocalDate
@ -19,9 +20,53 @@ class CalendarFactory {
fun getBeansOfThisWeek(): Array<CalendarBean> = getBeansOfWeek(LocalDate.now())
fun getBeansOfMonth(y: Int, m:Int): Array<CalendarBean> {
Log.d("CalendarFactory", "YearMonth.of(y, m) : ${YearMonth.of(y, m)}")
Log.d("CalendarFactory", "YearMonth.of(y, m).lengthOfMonth() : ${YearMonth.of(y, m).lengthOfMonth()}")
val daysInMonth = YearMonth.of(y, m).lengthOfMonth()
return Array<CalendarBean>(daysInMonth) {
val thisMonth = Array<CalendarBean>(daysInMonth) {
CalendarBean(y, m, it + 1)
}
val lastY = if (m != 1) y else y - 1
val lastM = if (m != 1) m - 1 else 12
val lastDaysInMonth = YearMonth.of(lastY, lastM).lengthOfMonth()
val lastMonth = Array<CalendarBean>(lastDaysInMonth) {
CalendarBean(lastY, lastM, it + 1)
}
var lastArray : Array<CalendarBean> = arrayListOf<CalendarBean>().run {
if (thisMonth[0].getDayOfWeek() != "SUNDAY") {
for (i in lastMonth.size - 1 downTo 0) {
this.add(lastMonth[i])
if (lastMonth[i].getDayOfWeek() == "SUNDAY") {
break
}
}
}
arrayOf<CalendarBean>() + this
}
val nextY = if (m != 12) y else y + 1
val nextM = if (m != 12) m + 1 else 1
val nextDaysInMonth = YearMonth.of(nextY, nextM).lengthOfMonth()
val nextMonth = Array<CalendarBean>(nextDaysInMonth) {
CalendarBean(nextY, nextM, it + 1)
}
var nextArray : ArrayList<CalendarBean> = arrayListOf()
val need = 42 - (thisMonth + lastArray).size
for (i in 0 until need) {
nextArray.add(nextMonth[i])
}
val r = lastArray.reversedArray() + thisMonth + nextArray
return r
}
fun getBeansOfMonth(pod: CalendarPod): Array<CalendarBean> = getBeansOfMonth(pod.year, pod.month)
fun getBeansOfThisMonth(): Array<CalendarBean> {
return LocalDate.now().run {
getBeansOfMonth(this.year, this.monthValue)
}
}
}

View File

@ -0,0 +1,21 @@
package com.example.calrendarview.model
import android.os.Build
import androidx.annotation.RequiresApi
import java.time.LocalDate
@RequiresApi(Build.VERSION_CODES.O)
class CalendarPod {
constructor(date: LocalDate) {
this.year = date.year
this.month = date.monthValue
}
constructor(y: Int, m: Int) {
this.year = y
this.month = m
}
val year: Int
val month: Int
}

View File

@ -1,5 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">

View File

@ -4,17 +4,18 @@
<attr name="item_layout" format="reference"/>
<attr name="numOfDayId" format="reference"/>
<declare-styleable name="BaseCustomViews">
<declare-styleable name="BaseCustomLayout">
<attr name="item_layout"/>
<attr name="numOfDayId"/>
</declare-styleable>
<declare-styleable name="DayView">
<declare-styleable name="DayLayout">
<!-- <attr name="item_layout"/>-->
<!-- <attr name="numOfDayId"/>-->
</declare-styleable>
<declare-styleable name="MonthView">
<declare-styleable name="WeekLayout">
<!-- <attr name="item_layout"/>-->
<!-- <attr name="numOfDayId"/>-->
</declare-styleable>
</resources>

View File

@ -172,7 +172,7 @@ class CalendarLayout : FrameLayout {
view!!.getHitRect(rect)
val isClick = rect.contains(ev.x.toInt(), ev.y.toInt())
Log.d(
TAG,
"tag",
"isClickView() called with: isClick = [$isClick]"
)
return isClick
@ -302,7 +302,7 @@ class CalendarLayout : FrameLayout {
}
companion object {
private const val TAG = "CalendarLayout"
private const val tag = "CalendarLayout"
const val TYPE_OPEN = 0

View File

@ -158,7 +158,7 @@ class CalendarView : ViewGroup {
}
}
Log.i(
TAG,
"tag",
"onMeasure() called with: itemHeight = [$itemHeight], itemWidth = [$itemWidth]"
)
lastwidthMeasureSpec = widthMeasureSpec
@ -199,6 +199,6 @@ class CalendarView : ViewGroup {
}
companion object {
private const val TAG = "CalendarView"
private const val tag = "CalendarView"
}
}

View File

@ -9,8 +9,8 @@ import com.example.accountbook.calendar2.CalendarLayoutListener
import com.example.accountbook.calendar2.CalendarManager
import com.example.accountbook.calendar2.CalendarPagerAdapter
import com.example.accountbook.databinding.CalendarActivityExampleBinding
import com.example.accountbook.databinding.ExDayViewBinding
import com.example.calrendarview.DayView
//import com.example.accountbook.databinding.ExDayLayoutBinding
import com.example.calrendarview.DayLayout
import com.example.calrendarview.model.CalendarBean
import com.example.calrendarview.model.CalendarFactory
import com.example.calrendarview.model.DayInfo
@ -26,9 +26,9 @@ class ActivityCalendarEx: AppCompatActivity() {
bind = CalendarActivityExampleBinding.inflate(this.layoutInflater)
// for (i in 0 until 7) {
val infos = CalendarFactory().getBeansOfThisWeek()
// val infos = CalendarFactory().getBeansOfThisWeek()
// bind.otherViews.numberOfRow = 7
// (bind.otherViews.getChildAt(i) as? DayView)?.dayInfo = infos.get(i)
// (bind.otherViews.getChildAt(i) as? DayLayout)?.infoDay = infos.get(i)
// }
setContentView(bind.root)
}

View File

@ -3,15 +3,20 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto">
<com.example.calrendarview.MonthView
android:id="@+id/otherViews"
<!-- <com.example.calrendarview.WeekLayout-->
<!-- android:id="@+id/otherViews"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="wrap_content"-->
<!-- app:layout_constraintTop_toTopOf="parent"-->
<!-- app:item_layout="@layout/ex_day_view"-->
<!-- app:numOfDayId="@id/ex_text_day"-->
<!-- />-->
<com.example.calrendarview.CalendarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_height="match_parent"
app:layout_constraintTop_toTopOf="parent"
app:item_layout="@layout/ex_day_view"
app:numOfDayId="@id/ex_text_day"
/>
app:numOfDayId="@id/ex_text_day" />
<!-- <com.example.accountbook.calendar2.CalendarLayout-->
<!-- android:id="@+id/calendarLayoutEx"-->
<!-- android:background="#dddddd"-->
@ -61,7 +66,7 @@
<!--&lt;!&ndash; app:layout_constraintBottom_toBottomOf="parent"&ndash;&gt;-->
<!--&lt;!&ndash; />&ndash;&gt;-->
<!-- </com.example.accountbook.calendar2.CalendarLayout>-->
<!-- <com.example.calrendarview.DayView-->
<!-- <com.example.calrendarview.DayLayout-->
<!-- android:id="@+id/test"-->
<!-- android:layout_width="match_parent"-->
<!-- android:layout_height="match_parent"-->

View File

@ -2,40 +2,38 @@
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_height="wrap_content"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:paddingVertical="10dp"
android:paddingHorizontal="5dp"
android:paddingHorizontal="1dp"
>
<TextView
android:id="@+id/ex_text_day"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
android:gravity="end|center_vertical"
android:gravity="center"
android:text="01일"
android:textSize="15dp"
android:textSize="12dp"
/>
<TextView
android:id="@+id/ex_text_day_view_01"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/ex_text_day"
android:gravity="end|center_vertical"
android:gravity="start|center_vertical"
android:text="ex_text_day"
android:textSize="12dp"
android:background="#9acd32"
android:layout_marginTop="5dp"
android:textSize="8dp"
android:layout_marginTop="8dp"
/>
<TextView
android:id="@+id/ex_text_day_view_02"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@id/ex_text_day_view_01"
android:gravity="end|center_vertical"
android:gravity="start|center_vertical"
android:text="ex_text_day"
android:textSize="12dp"
android:background="#dda0dd"
android:layout_marginTop="5dp"
android:textSize="8dp"
android:layout_marginTop="3dp"
/>
</androidx.constraintlayout.widget.ConstraintLayout>