A highly customizable calendar library for Android, powered by RecyclerView.

Overview

CalendarView

A highly customizable calendar library for Android, powered by RecyclerView.

CI JitPack License Twitter

With this library, your calendar will look however you want it to.

Preview

Features

  • Single or range selection - The library provides the calendar logic which enables you to implement the view whichever way you like.
  • Week or month mode - show 1 row of weekdays, or any number of rows from 1 to 6.
  • Disable desired dates - Prevent selection of some dates by disabling them.
  • Boundary dates - limit the calendar date range.
  • Custom date view - make your day cells look however you want, with any functionality you want.
  • Custom calendar view - make your calendar look however you want, with whatever functionality you want.
  • Custom first day of the week - Use any day as the first day of the week.
  • Horizontal or vertical scrolling mode.
  • Month headers and footers - Add headers/footers of any kind on each month.
  • Easily scroll to any date or month view using the date.
  • Use all RecyclerView customisations(decorators etc) since CalendarView extends from RecyclerView.
  • Design your calendar however you want. The library provides the logic, you provide the views.

Sample project

It's very important to check out the sample app. Most techniques that you would want to implement are already implemented in the examples.

Download the sample app here

View the sample app's source code here

Setup

The library uses java.time classes via Java 8+ API desugaring for backward compatibility since these classes were added in Java 8.

Step 1

To setup your project for desugaring, you need to first ensure that you are using Android Gradle plugin 4.0.0 or higher.

Then include the following in your app's build.gradle file:

android {
  defaultConfig {
    // Required ONLY when setting minSdkVersion to 20 or lower
    multiDexEnabled true
  }

  compileOptions {
    // Flag to enable support for the new language APIs
    coreLibraryDesugaringEnabled true
    // Sets Java compatibility to Java 8
    sourceCompatibility JavaVersion.VERSION_1_8
    targetCompatibility JavaVersion.VERSION_1_8
  }
}

dependencies {
  coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:<latest-version>'
}

You can find the latest version of desugar_jdk_libs here.

Step 2

Add the JitPack repository to your project level build.gradle:

allprojects {
 repositories {
    google()
    jcenter()
    maven { url "https://jitpack.io" }
 }
}

Add CalendarView to your app build.gradle:

dependencies {
	implementation 'com.github.kizitonwose:CalendarView:<latest-version>'
}

You can find the latest version of CalendarView on the JitPack badge above the preview images.

Note: If you're upgrading from version 0.3.x to 0.4.x or 1.x.x, see the migration guide.

Usage

Step 1

Add CalendarView to your XML like any other view.

<com.kizitonwose.calendarview.CalendarView
    android:id="@+id/calendarView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    app:cv_dayViewResource="@layout/calendar_day_layout" />

See all available attributes.

Create your day view resource in res/layout/calendar_day_layout.xml.

<TextView
    android:id="@+id/calendarDayText"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="16sp"
    tools:text="22" />

Create your view container which acts as a view holder for each date cell. The view passed in here is the inflated day view resource which you provided.

class DayViewContainer(view: View) : ViewContainer(view) {    
    val textView = view.findViewById<TextView>(R.id.calendarDayText)

    // With ViewBinding
    // val textView = CalendarDayLayoutBinding.bind(view).calendarDayText
}

Provide a DayBinder for the CalendarView using your DayViewContainer type.

calendarView.dayBinder = object : DayBinder<DayViewContainer> {
    // Called only when a new container is needed.
    override fun create(view: View) = DayViewContainer(view)
    
    // Called every time we need to reuse a container.
    override fun bind(container: DayViewContainer, day: CalendarDay) {
        container.textView.text = day.date.dayOfMonth.toString()
    }
}

Step 2

Setup the desired dates in your Fragment or Activity:

val currentMonth = YearMonth.now()
val firstMonth = currentMonth.minusMonths(10)
val lastMonth = currentMonth.plusMonths(10)
val firstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek
calendarView.setup(firstMonth, lastMonth, firstDayOfWeek)
calendarView.scrollToMonth(currentMonth)

And that's all you need for a simple usage!

To add a header or footer to each month, the procedure is the same. Just provide your monthHeaderResource or monthFooterResource attribute, then set the monthHeaderBinder or monthFooterBinder property of the CalendarView. For more complex usages, please see the sample project.

In the example above, we get the first day of the week from the current locale, however, we can use a specific day regardless of locale by passing in the value DayOfWeek.SUNDAY, DayOfWeek.MONDAY etc

Attributes

XML (All prefixed cv_ for clarity)

  • dayViewResource: The xml resource that is inflated and used as the day cell view. This must be provided.

  • monthHeaderResource: The xml resource that is inflated and used as a header for every month.

  • monthFooterResource: The xml resource that is inflated and used as a footer for every month.

  • orientation: The calendar orientation, can be horizontal or vertical. Default is vertical.

  • scrollMode: The scrolling behavior of the calendar. Can be paged or continuous. If paged, the calendar will snap to the nearest month after a scroll or swipe action. Default value is continuous.

  • maxRowCount: The maximum number of rows(1 to 6) to show on each month. If a month has a total of 6 rows and maxRowCount is set to 4, there will be two appearances of that month on the calendar, the first one will show 4 rows and the second one will show the remaining 2 rows. To show a week mode calendar, set this value to 1, you may also want to set hasBoundaries to false so dates can overflow into the previous/next month for a better experience.

  • hasBoundaries: Determines if dates of a month should stay in its section or can flow into another month's section. If true, a section can only contain dates belonging to that month, its inDates and outDates. if false, the dates are added continuously, irrespective of month sections.

    When this property is false, a few things behave slightly differently:

    • If inDateStyle is either allMonths or firstMonth, only the first index will contain inDates.
    • If outDateStyle is either endOfRow or endOfGrid, only the last index will contain outDates.
    • If outDateStyle is endOfGrid, outDates are generated for the last index until it satisfies the maxRowCount requirement.
  • inDateStyle: This Determines how inDates are generated for each month on the calendar. If set to allMonths, the calendar will generate inDates for all months, if set to firstMonth inDates will be generated for the first month only and if set to none, inDates will not be generated, this means that there will be no offset on any month.

  • outDateStyle: This determines how outDates are generated for each month on the calendar. If endOfRow , the calendar will generate outDates until it reaches the first end of a row. This means that if a month has 6 rows, it will display 6 rows and if a month has 5 rows, it will display 5 rows. However, if this value is set to endOfGrid, the calendar will generate outDates until it reaches the end of a 6 x 7 grid. This means that all months will have 6 rows.

If you are wondering what outDates and inDates mean, let's use the screenshot below as an example.

inDate and outDates

In the image, the dates within the green annotation are inDates, the ones within the red annotation are outDates while those without annotation are monthDates. You can check for this when binding your calendar. To achieve the exact effect on the image, we do this:

calendarView.dayBinder = object : DayBinder<DayViewContainer> {
    override fun create(view: View) = DayViewContainer(view)
    override fun bind(container: DayViewContainer, day: CalendarDay) {
        container.textView.text = day.date.dayOfMonth.toString()
        if (day.owner == DayOwner.THIS_MONTH) {
            container.textView.setTextColor(Color.WHITE)
        } else {
            container.textView.setTextColor(Color.GRAY)
        }
    }
}

inDates have their owner property set to DayOwner.PREVIOUS_MONTH

outDates have their owner property set to DayOwner.NEXT_MONTH

monthDates have their owner property set to DayOwner.THIS_MONTH as seen in the code snippet above.

Properties

All XML attributes are also available as properties of the CalendarView class via code. So in addition to those, we have:

  • monthScrollListener: Called when the calendar scrolls to a new month. Mostly beneficial if scrollMode is paged.

  • dayBinder: An instance of DayBinder for managing day cell views.

  • monthHeaderBinder: An instance of MonthHeaderFooterBinder for managing header views.

  • monthFooterBinder: An instance of MonthHeaderFooterBinder for managing footer views.

  • daySize: The size, in pixels for each day cell view.

Note that setting the daySize property to CalendarView.SIZE_SQUARE makes the day cells have equal width and height which is basically the width of the calendar divided by 7. SIZE_SQUARE is the default size value.

Methods

  • scrollToDate(date: LocalDate): Scroll to a specific date on the calendar. Use smoothScrollToDate() to get a smooth scrolling animation.

  • scrollToMonth(month: YearMonth): Scroll to a month on the calendar. Use smoothScrollToMonth() to get a smooth scrolling animation.

  • notifyDateChanged(date: LocalDate): Reload the view for the specified date.

  • notifyMonthChanged(month: YearMonth): Reload the header, body and footer views for the specified month.

  • notifyCalendarChanged(): Reload the entire calendar.

  • findFirstVisibleMonth() and findLastVisibleMonth(): Find the first and last visible months on the CalendarView respectively.

  • findFirstVisibleDay() and findLastVisibleDay(): Find the first and last visible days on the CalendarView respectively.

  • setupAsync(): Setup the CalendarView, asynchronously, useful if your startMonth and endMonth values are many years apart.

  • updateMonthRange(): Update the CalendarView's startMonth and/or endMonth values after the initial setup. The currently visible month is preserved. Use updateMonthRangeAsync() to do this asynchronously.

  • updateMonthConfiguration(): Update inDateStyle, outDateStyle, maxRowCount and hasBoundaries properties without generating the underlying calendar data repeatedly. Prefer this if setting more than one of these properties at the same time. Use updateMonthConfigurationAsync() to do this asynchronously.

There's no need to list all available methods or repeating the documentation here. Please see the CalendarView class for all properties and methods available with proper documentation.

Date clicks

You should set a click listener on the view which is provided to the view container.

XML file for the date cell calendar_day_layout.xml:

<!--We'll use this TextView to show the dates-->
<TextView
    android:id="@+id/calendarDayText"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:gravity="center"
    android:textSize="16sp"
    tools:text="22" />

Of course, you need to set the file as cv_dayViewResource on the CalendarView:

<com.kizitonwose.calendarview.CalendarView
    android:id="@+id/calendarView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cv_dayViewResource="@layout/calendar_day_layout" />

Click listener implementation in your Fragment or Activity:

class DayViewContainer(view: View) : ViewContainer(view) {
    val textView = view.findViewById<TextView>(R.id.calendarDayText)
    // Will be set when this container is bound
    lateinit var day: CalendarDay
    
    init {
        view.setOnClickListener {
            // Use the CalendarDay associated with this container.
        }
    }
}

calendarView.dayBinder = object : DayBinder<DayViewContainer> {
    override fun create(view: View) = DayViewContainer(view)
    override fun bind(container: DayViewContainer, day: CalendarDay) {
        // Set the calendar day for this container.
        container.day = day
        // Set the date text
        container.textView.text = day.date.dayOfMonth.toString()
        // Other binding logic
    }
}

Date Selection

The library has no inbuilt concept of selected/unselected dates, this gives you the freedom to choose how best you would like to implement this use case.

Implementing date selection is as simple as showing a background on a specific date in the date binder, remember that since CalendarView is a RecyclerView, you need to undo any special effects on dates where it is not needed.

For this example, I want only the last clicked date to be selected on the calendar.

Firstly, let's keep a reference to the selected date:

private var selectedDate: LocalDate? = null

Next, using the click logic already shown in the date click section above, we update this field whenever a date is clicked and show the selection background on the clicked date.

view.setOnClickListener {
    // Check the day owner as we do not want to select in or out dates.
    if (day.owner == DayOwner.THIS_MONTH) {
        // Keep a reference to any previous selection
        // in case we overwrite it and need to reload it.
        val currentSelection = selectedDate
        if (currentSelection == day.date) {
            // If the user clicks the same date, clear selection.
            selectedDate = null
            // Reload this date so the dayBinder is called
            // and we can REMOVE the selection background.
            calendarView.notifyDateChanged(currentSelection)
        } else {
            selectedDate = day.date
            // Reload the newly selected date so the dayBinder is
            // called and we can ADD the selection background.
            calendarView.notifyDateChanged(day.date)
            if currentSelection != null {
                // We need to also reload the previously selected 
                // date so we can REMOVE the selection background.
                calendarView.notifyDateChanged(currentSelection)
            }
        }
    }
}

Lastly, we implement the dayBinder to reflect the selection accordingly:

calendarView.dayBinder = object : DayBinder<DayViewContainer> {
    override fun create(view: View) = DayViewContainer(view)
    override fun bind(container: DayViewContainer, day: CalendarDay) {
        container.day = day
        val textView = container.textView
        textView.text = day.date.dayOfMonth.toString()
        if (day.owner == DayOwner.THIS_MONTH) {
            // Show the month dates. Remember that views are recycled!
            textView.visibility = View.VISIBLE
            if (day.date == selectedDate) {
                // If this is the selected date, show a round background and change the text color.
                textView.setTextColor(Color.WHITE)
                textView.setBackgroundResource(R.drawable.selection_background)
            } else {
                // If this is NOT the selected date, remove the background and reset the text color.
                textView.setTextColor(Color.BLACK)
                textView.background = null
            }
        } else {
            // Hide in and out dates
            textView.visibility = View.INVISIBLE
        }
    }
}

For more complex selection logic like range selection, please see the sample project. It's quite simple, the magic is all in your binding logic!

Disabling dates

As expected, the library does not provide this logic internally so you have complete flexibility.

To disable dates, you can simply set the texts on those dates to look "disabled" and ignore clicks on those dates. For example, if we want to show in and out dates but "disable" them so that they cannot be selected, we can just set the alpha property for those dates in the dayBinder to give the effect of being disabled.

Continuing with the example in the date selection section, we already ignore clicks for in and out dates using this logic:

view.setOnClickListener {
    // Check the day owner as we do not want to select in or out dates.
    if (day.owner == DayOwner.THIS_MONTH) {
        // Only use month dates
    }
}

Then in the dayBinder, we check the day owner again and bind accordingly:

calendarView.dayBinder = object : DayBinder<DayViewContainer> {
    override fun create(view: View) = DayViewContainer(view)
    override fun bind(container: DayViewContainer, day: CalendarDay) {
        container.day = day
        val textView = container.textView
        textView.text = day.date.dayOfMonth.toString()
        textView.alpha = if (day.owner == DayOwner.THIS_MONTH) 1f else 0.3f
}

And that's all you need to do. Of course you can go wild and do a whole lot more, see the sample project for some complex implementations.

Adding month headers and footers

This is quite simple, just provide the needed values for cv_monthHeaderResource or cv_monthFooterResource in XML or programmatically. In the example shown below, we add a header which simply shows the month name above each month:

Create the header view in res/layout/calendar_month_header_layout.xml:

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/headerTextView"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:padding="16dp"
    android:textSize="26sp"
    tools:text="October 2019" />

Set the view as the month header resource:

<com.kizitonwose.calendarview.CalendarView
    android:id="@+id/calendarView"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:cv_dayViewResource="@layout/calendar_day_layout"
    app:cv_monthHeaderResource="@layout/calendar_month_header_layout" />

Finally, provide a month header binder in code:

class MonthViewContainer(view: View) : ViewContainer(view) {
    val textView = view.findViewById<TextView>(R.id.headerTextView)
}
calendarView.monthHeaderBinder = object : MonthHeaderFooterBinder<MonthViewContainer> {
    override fun create(view: View) = MonthViewContainer(view)
    override fun bind(container: MonthViewContainer, month: CalendarMonth) {
        container.textView.text = "${month.yearMonth.month.name.toLowerCase().capitalize()} ${month.year}"
    }
}

The same logic applies if you need to add a footer.

First day of the week

Here's a method which generates the weekdays from the user's current Locale.

fun daysOfWeekFromLocale(): Array<DayOfWeek> {
    val firstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek
    val daysOfWeek = DayOfWeek.values()
    // Order `daysOfWeek` array so that firstDayOfWeek is at index 0.
    // Only necessary if firstDayOfWeek is not DayOfWeek.MONDAY which has ordinal 0.
    if (firstDayOfWeek != DayOfWeek.MONDAY) {
        val rhs = daysOfWeek.sliceArray(firstDayOfWeek.ordinal..daysOfWeek.indices.last)
        val lhs = daysOfWeek.sliceArray(0 until firstDayOfWeek.ordinal)
        return = rhs + lhs
    }
    return daysOfWeek
}

With the method above, you can set up the calendar so the first day of the week is what the user would expect. This could be Sunday, Monday or whatever the Locale returns:

val daysOfWeek = daysOfWeekFromLocale()
calendarView.setup(startMonth, endMonth, daysOfWeek.first())

Of course, this could be simplified as:

val firstDayOfWeek = WeekFields.of(Locale.getDefault()).firstDayOfWeek
calendarView.setup(startMonth, endMonth, firstDayOfWeek)

However, you would typically use the daysOfWeek array values to set up the weekday texts in your month header view, this way it matches what is shown on the calendarView.

To use Sunday as the first day of the week, regardless of the user's Locale, use the below logic instead:

val daysOfWeek = arrayOf(
    DayOfWeek.SUNDAY,
    DayOfWeek.MONDAY,
    DayOfWeek.TUESDAY,
    DayOfWeek.WEDNESDAY,
    DayOfWeek.THURSDAY,
    DayOfWeek.FRIDAY,
    DayOfWeek.SATURDAY
)
calendarView.setup(startMonth, endMonth, daysOfWeek.first())
// Use the daysOfWeek to set up your month header texts:
// Sun | Mon | Tue | Wed | Thu | Fri | Sat

Week view and Month view

This library has no concept of week/month view. You'll need to configure the calendar to mimic this behavior by changing its state between a 6 or 1 row calendar, depending on your needs. This feature can be seen in Example 1 in the sample app. In summary, here's what you need:

<!-- Common configurations for both modes. -->
app:cv_orientation="horizontal"
app:cv_outDateStyle="endOfRow"
app:cv_inDateStyle="allMonths"
app:cv_scrollMode="paged"
val monthToWeek = monthViewCheckBox.isChecked
if (monthToWeek) { 
    // One row calendar for week mode
    calendarView.updateMonthConfiguration(
        inDateStyle = InDateStyle.ALL_MONTHS,
        maxRowCount = 1,
        hasBoundaries = false
    )
} else {
    // Six row calendar for month mode
    calendarView.updateMonthConfiguration(
        inDateStyle = InDateStyle.FIRST_MONTH,
        maxRowCount = 6,
        hasBoundaries = true
    )
}

With the configuration above, you get the result below:

Week and month modes

If you wish to animate height changes on the CalendarView when switching between week and month modes, please see Example 1 in the sample app where we use a ValueAnimator, of course you can use whichever animation logic you prefer.

You can also set hasBoundaries to true for a week mode calendar. This helps the library make very few optimizations, however, you should also change scrollMode to ScrollMode.CONTINUOUS as pagination behavior may not be as expected due to boundary limitations. See Example 7 in the sample app for a week mode calendar with this configuration, a screenshot is shown below:

Week mode

Remember that all the screenshots above are just examples of what you can achieve with this library and you can absolutely build your calendar to look however you want.

Made a cool calendar with this library? Share an image here.

FAQ

Q: How do I use this library in a Java project?

A: It works out of the box, however, the MonthScrollListener is not an interface but a Kotlin function. To set the MonthScrollListener in a Java project see this.

Q: How do I disable user scrolling on the calendar so I can only scroll programmatically?

A: See this.

Q: Why am I getting the same YearMonth value in the CalendarMonth passed into the MonthScrollListener?

A: This is because you have set app:cv_hasBoundaries to false in XML or have called calendarView.hasBoundaries = false in code. When this is set, the underlying YearMonth is undefined on all indices as each index could have multiple months depending on your maxRowCount value. If you need the month value with the hasBoundaries = false setting, you can get it from any of the CalendarDay values in the CalendarMonth class. You can always check if the first and last dates are from different months and act accordingly.

Migration

If you're upgrading from version 0.3.x to 0.4.x or 1.x.x, the main change is that CalendarView moved from using ThreeTenABP to Java 8 API desugaring for dates. After following the new setup instructions, the next thing you need to do is change your imports for date/time related classes from org.threeten.bp.* to java.time.*.

You also need to remove the line AndroidThreeTen.init(this) from the onCreate() method of your application class as it's no longer needed.

Contributing

Found a bug? feel free to fix it and send a pull request or open an issue.

Inspiration

CalendarView was inspired by the iOS library JTAppleCalendar. I used JTAppleCalendar in an iOS project but couldn't find anything as customizable on Android so I built this. You'll find some similar terms like InDateStyle, OutDateStyle, DayOwner etc.

License

CalendarView is distributed under the MIT license. See LICENSE for details.

Comments
  • Monthly calendar view is not showing all days

    Monthly calendar view is not showing all days

    Version: 0.4.5 Device: Xiaomi Mi A3, Android 10, 720x1560

    When swiping through months, specifically when April is selected, calendar does not show all days. I've tried with notifyMonthChanged(month: YearMonth) but without success. Please advise.

    Recording: https://drive.google.com/file/d/1fXa9UL3pae6B-SiUKEDGZ9-AJ9OB79WS/view

    And an image: calendarbug

    opened by batadamnjanovic 19
  • IndexOutOfBoundsException causing a lot of crashes

    IndexOutOfBoundsException causing a lot of crashes

    I'm using this library in my application, recently i started to receive a large amount of crash reports from my users. I cannot reproduce the issue while debugging. I'm using the latest version of the library.

    com.kizitonwose.calendarview.ui.CalendarAdapter.notifyMonthScrollListenerIfNeeded (CalendarAdapter.kt:197)
    com.kizitonwose.calendarview.ui.CalendarAdapter$notifyMonthScrollListenerIfNeeded$1.onAnimationsFinished (CalendarAdapter.kt:191)
    androidx.recyclerview.widget.RecyclerView$ItemAnimator.dispatchAnimationsFinished (RecyclerView.java:13751)
    androidx.recyclerview.widget.DefaultItemAnimator.dispatchFinishedWhenDone (DefaultItemAnimator.java:551)
    androidx.recyclerview.widget.DefaultItemAnimator$5.onAnimationEnd (DefaultItemAnimator.java:249)
    android.view.ViewPropertyAnimator$AnimatorEventListener.onAnimationEnd (ViewPropertyAnimator.java:1111)
    android.animation.Animator$AnimatorListener.onAnimationEnd (Animator.java:554)
    android.animation.ValueAnimator.endAnimation (ValueAnimator.java:1242)
    android.animation.ValueAnimator.cancel (ValueAnimator.java:1127)
    android.view.ViewPropertyAnimator.cancel (ViewPropertyAnimator.java:424)
    androidx.recyclerview.widget.DefaultItemAnimator.cancelAll (DefaultItemAnimator.java:642)
    androidx.recyclerview.widget.DefaultItemAnimator.endAnimations (DefaultItemAnimator.java:634)
    androidx.recyclerview.widget.RecyclerView.removeAndRecycleViews (RecyclerView.java:1205)
    androidx.recyclerview.widget.RecyclerView.setAdapterInternal (RecyclerView.java:1236)
    androidx.recyclerview.widget.RecyclerView.setAdapter (RecyclerView.java:1194)
    com.kizitonwose.calendarview.CalendarView.invalidateViewHolders (CalendarView.kt:411)
    com.kizitonwose.calendarview.CalendarView.onMeasure (CalendarView.kt:300)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552)
    android.widget.LinearLayout.measureVertical (LinearLayout.java:842)
    android.widget.LinearLayout.onMeasure (LinearLayout.java:721)
    android.view.View.measure (View.java:26415)
    androidx.constraintlayout.widget.ConstraintLayout$Measurer.measure (ConstraintLayout.java:811)
    androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measure (BasicMeasure.java:466)
    androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.measureChildren (BasicMeasure.java:134)
    androidx.constraintlayout.core.widgets.analyzer.BasicMeasure.solverMeasure (BasicMeasure.java:278)
    androidx.constraintlayout.core.widgets.ConstraintWidgetContainer.measure (ConstraintWidgetContainer.java:120)
    androidx.constraintlayout.widget.ConstraintLayout.resolveSystem (ConstraintLayout.java:1593)
    androidx.constraintlayout.widget.ConstraintLayout.onMeasure (ConstraintLayout.java:1700)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.FrameLayout.onMeasure (FrameLayout.java:194)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasureChild (CoordinatorLayout.java:760)
    com.google.android.material.appbar.HeaderScrollingViewBehavior.onMeasureChild (HeaderScrollingViewBehavior.java:99)
    com.google.android.material.appbar.AppBarLayout$ScrollingViewBehavior.onMeasureChild (AppBarLayout.java:2003)
    androidx.coordinatorlayout.widget.CoordinatorLayout.onMeasure (CoordinatorLayout.java:831)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.FrameLayout.onMeasure (FrameLayout.java:194)
    androidx.appcompat.widget.ContentFrameLayout.onMeasure (ContentFrameLayout.java:145)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552)
    android.widget.LinearLayout.measureVertical (LinearLayout.java:842)
    android.widget.LinearLayout.onMeasure (LinearLayout.java:721)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.FrameLayout.onMeasure (FrameLayout.java:194)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.LinearLayout.measureChildBeforeLayout (LinearLayout.java:1552)
    android.widget.LinearLayout.measureVertical (LinearLayout.java:842)
    android.widget.LinearLayout.onMeasure (LinearLayout.java:721)
    android.view.View.measure (View.java:26415)
    android.view.ViewGroup.measureChildWithMargins (ViewGroup.java:7845)
    android.widget.FrameLayout.onMeasure (FrameLayout.java:194)
    com.android.internal.policy.DecorView.onMeasure (DecorView.java:1013)
    android.view.View.measure (View.java:26415)
    android.view.ViewRootImpl.performMeasure (ViewRootImpl.java:3606)
    android.view.ViewRootImpl.measureHierarchy (ViewRootImpl.java:2349)
    android.view.ViewRootImpl.performTraversals (ViewRootImpl.java:2641)
    android.view.ViewRootImpl.doTraversal (ViewRootImpl.java:2201)
    android.view.ViewRootImpl$TraversalRunnable.run (ViewRootImpl.java:9000)
    android.view.Choreographer$CallbackRecord.run (Choreographer.java:996)
    android.view.Choreographer.doCallbacks (Choreographer.java:794)
    android.view.Choreographer.doFrame (Choreographer.java:729)
    android.view.Choreographer$FrameDisplayEventReceiver.run (Choreographer.java:981)
    android.os.Handler.handleCallback (Handler.java:883)
    android.os.Handler.dispatchMessage (Handler.java:100)
    android.os.Looper.loop (Looper.java:237)
    android.app.ActivityThread.main (ActivityThread.java:7948)
    java.lang.reflect.Method.invoke (Method.java)
    com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run (RuntimeInit.java:493)
    com.android.internal.os.ZygoteInit.main (ZygoteInit.java:1075) 
    
    opened by mohakapt 18
  • ERROR: Failed to resolve: com.github.kizitonwose:CalendarView:0.3.2

    ERROR: Failed to resolve: com.github.kizitonwose:CalendarView:0.3.2

    Hello I have created a basic project in Android Studio but cannot import this library. The compiledSdkVersion is 28. And I have well added the maven repository in the Project build.gradle. And in the Module build.gradle I have added the following line in the dependencies section : implementation 'com.github.kizitonwose:CalendarView:0.3.2'

    opened by reuniware 16
  • Height doesn't adjust for each month with wrap_content on horizontal paged calendar

    Height doesn't adjust for each month with wrap_content on horizontal paged calendar

    Steps to reproduce

    1. I've added calendar view with wrap_content
    <com.kizitonwose.calendarview.CalendarView
                android:id="@+id/cv_custom_calendar"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:layout_marginEnd="8dp"
                app:cv_dayViewResource="@layout/calendar_day"
                app:cv_hasBoundaries="true"
                app:cv_outDateStyle="none"
                app:cv_monthHeaderResource="@layout/calendar_header"
                app:cv_orientation="horizontal"
                app:cv_scrollMode="paged"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_month_year" />
    
    1. Open fragment for the first time, scroll to the previous month and height of the CalendarView stays the same even though the number of days and rows increased
    2. Open the same fragment again, resize works.

    Note: Is this an edge case because February starts on Monday with 28 days and it has 4 rows? With fixed android:layout_height it shows all dates, but doesn't look nice with extra space at the bottom. Also, I can't find the right height that will show all days for every screen size.

    Is there a possibility to have fixed size and spacing between rows to be auto-adjusted?

    Device: Samsung S8, Samsung A5 2017

    Video: https://vimeo.com/user133404315/review/511093300/5daa85a221

    opened by nikolasamardzija 14
  • Issue while using dayBinder with MonthscrollListener

    Issue while using dayBinder with MonthscrollListener

    Hi Kizitonwose, We are getting calendar data from remote api for 3 years, current previous and next. how to use daybinder for each month of the year according to data i received from the API. How to put condition on dates to change the background of the day of particular month accordingly in daybinder. { "2019": [

    ], "2020": [

    ], "2021": [ { "sd": 1577212200000, "ed": 0, "desc": "Christmas-Mumbai-India-2019", "typ": "H", "status": 0, "timeDate": null }, { "sd": 1586716200000, "ed": 1586716200000, "desc": "Vaisahkhi", "typ": "F", "status": 0, "sdd": 0, "edd": 0, "levtype": 0, "datetobechecked": 0, "timeDate": "2020-04-13", "shortName": null }, { "sd": 1602268200000, "ed": 1602268200000, "desc": "Lev_124423268", "typ": "L", "status": 3, "sdd": 3, "edd": 3, "levtype": 0, "datetobechecked": 0, "timeDate": "2020-10-10", "shortName": null }, { "sd": 1578076200000, "ed": 0, "desc": "Project Weekend-Saturday ", "typ": "W", "status": 0, "timeDate": null }, { "sd": 1578162600000, "ed": 0, "desc": "Project Weekend-Sunday ", "typ": "W", "status": 0, "timeDate": null } ] }

    Above is the response structure. Like this data for every year will come. typ - W - weekend, F - Flexi, H- Holiday, L - Leave for all this flag i want to change the background of the day according to response. but somehow i am failing to do this. how to achieve this.

    Currrently on monthscrollListener i am getting the list of model object for month. but how to bind that data to daybinder on monthscrollListener.

    opened by Nildevelope 13
  • When endOfRow outDateStyle is used, once 6th row disappears, it never shows again

    When endOfRow outDateStyle is used, once 6th row disappears, it never shows again

    For example, if I'm in June, it has 6th row, and it shows, but once I move to July which only has 5 rows, and come back to June, June still only shows 5 rows, and final June days are obviously missing.

    opened by gajicm93 12
  • Compose wrapper

    Compose wrapper

    Have you considered creating a compose wrapper over CalendarView? I'm not talking about total rewrite, but about a separate artifact with CalendarView as composable function. It would be nothing more then a wrapper using AndroidView, but until some new fully compose calendar will stabilize - this should work just fine.

    If you're fine with that i think i'll try and find some time to create a PR with that

    opened by jakoss 11
  • Setting of day width/height

    Setting of day width/height

    It seems like it's impossible to change the width and height of the day cells independent of one another. From what I can tell, setting either the height or width turns off autoSize. I feel like the API mislead me into thinking I could reduce the space between rows (while keeping the width the same) by simply changing the height because they are separate properties.

    Perhaps it should be one method that accepts width and height instead?

    While a single function would be a step in the right direction, I think this way of setting the cell size is a bit confusing. I expected the library to respect the height and width set on the dayViewRes, but instead it ignores it, sets it to match_parent, and uses dayWidth and dayHeight from CalendarView as the sources of truth.

    I think this is a bit of a gotcha and it would be helpful to have this behavior documented. Ideally, the user's layout determines the cell size.

    For anyone wondering how to reduce the space between rows, here's how I did it:

    // View.doOnPreDraw is found in core-ktx
    doOnPreDraw {
      dayWidth = calendarView.width / 7
      dayHeight = (dayWidth * .666).toInt()
    }
    
    opened by luis-cortes 11
  • translating to java

    translating to java

    hi i need some help

    1. dotView.isVisible = events[day.date].orEmpty().isNotEmpty() what is this line in java, sorry im still cant really understand kotlin language

    2)class Example3EventsAdapter(val onClick: (Event) -> Unit) : RecyclerView.Adapter<Example3EventsAdapter.Example3EventsViewHolder>() {

    val events = mutableListOf<Event>()
    
    1. inner class Example3EventsViewHolder(override val containerView: View) : RecyclerView.ViewHolder(containerView), LayoutContainer {

       init {
           itemView.setOnClickListener {
               onClick(events[adapterPosition])
           }
       }
      
       fun bind(event: Event) {
           itemEventText.text = event.text
       }
      

      }

    opened by ghost 11
  • Calendar sometimes scrolls to first month, on visibility change.

    Calendar sometimes scrolls to first month, on visibility change.

    Pretty basic setup, and when I toggle calendar visibility, the calendar sometimes scrolls to first month. It is just random. At first I thought it was some action on my end, and I've debugged it thoroughly, and followed the flow, nothing special apart from visibility change from gone to visible, and calendar just jumps to the first month set instead of staying at currently set month.

    opened by slobodanantonijevic 10
  • Set dayHeight to

    Set dayHeight to "wrap_content"

    Hi! Thanks for this awesome library.

    I noticed the calendar will cut the day cells if the height is greater than "DAY_SIZE_SQUARE". Is possible to have a way of telling the widget to set the day cells height to "wrap content" so everything inside will always be visible (without manually calculate the correct height)?

    Thanks

    opened by unveloper 9
  • Calendar Events Not Saving

    Calendar Events Not Saving

    Library information:

    • Version: 2.0.0
    • View or Compose module: View

    Question:

    I created some custom Events for the end-user to use via a custom Alert Dialog. I see the events saving initially, but when I close out of the Calendar and come back in, the events are gone. I am relatively new to Kotlin programming, so I am sure I am missing something with making sure the UUID events are able to be accessed on a new instance of the application. Do you have any ideas on what I should look at?

    I am able to provide any code you need, but the main things I changed from the stock code were the custom Alert dialog and the visual aspects.

    opened by gusterfan2180 0
  • After generate Release sign api  Calenderview.setup function throw error

    After generate Release sign api Calenderview.setup function throw error

    Library information:

    • Version:2.0.4
    • View or Compose module: calenderview.setup(startMonth, endMonth, SUNDAY);

    Describe the bug**

    A clear and concise description of what the bug is. when i set the calenderview with start month and end month and day of week it will work fine on debugable application but once i generated sign apk it was not work and throw error

    Fatal Exception: java.lang.NoSuchMethodError No virtual method between(Lj$/time/temporal/Temporal;Lj$/time/temporal/Temporal;)J in class Lj$/time/temporal/ChronoUnit; or its super classes (declaration of 'j$.time.temporal.ChronoUnit' appears in /data/app/~~iLExDRd_EWQEtJRSVe7vRg==/com.plapdc.production-L1BjoCyZD5U8Yv-KGydiVA==/base.apk!classes2.dex)

    com.kizitonwose.calendar.data.MonthDataKt.getMonthIndex (MonthData.kt:87) com.kizitonwose.calendar.data.MonthDataKt.getMonthIndicesCount (MonthData.kt:92) com.kizitonwose.calendar.view.internal.monthcalendar.MonthCalendarAdapter. (MonthCalendarAdapter.kt:39) com.kizitonwose.calendar.view.CalendarView.setup (CalendarView.kt:401)

    this all were error logs

    To Reproduce (if applicable)

    Steps to reproduce the behavior:

    1. Go to
    2. Click on '....'
    3. See '....'

    Expected behavior (if applicable)

    A clear and concise description of what you expected to happen.

    Screenshots? (if applicable)

    If applicable, add screenshots or screen recordings to help explain the problem.

    Additional information

    Add any other information about the bug here.

    https://user-images.githubusercontent.com/30427424/209964519-4f078e82-c22b-40f8-9a60-226fd4472970.mp4

    opened by KjMithawala 0
Releases(2.1.1)
  • 2.1.1(Dec 26, 2022)

  • 2.1.0(Dec 11, 2022)

    Compose:

    • Update compose UI version to 1.3.2
    • Use SnapFlingBehavior provided by the compose framework for pagination instead of the snapper library.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.4(Nov 17, 2022)

  • 2.0.3(Nov 14, 2022)

    Compose:

    • Introduce ContentHeightMode enum which determines how the height of the day content is calculated.
    • Allow null header and footer parameters.

    View:

    • Internal optimizations for DaySize behavior implementation.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.2(Nov 11, 2022)

    View:

    • Add rectangle DaySize option that allows the calendar to fill the parent's size.
    • Remove the internal view used to wrap the day cells as they are no longer needed.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.1(Oct 31, 2022)

    View:

    • The default item animator is no longer used internally, you can set an item animator if desired.
    • The footer binder is called after the body content is bound.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Oct 15, 2022)

    What's new:


    Breaking changes in the view-based CalendarView class:

    • async() methods have been removed as the calendar is now capable of handling really large date ranges without performance issues. The calendar data is generated as needed. The removed methods are setupAsync() and updateMonthRangeAsync(). Please use the methods setup() and updateMonthData().

    • updateMonthRange() method has been renamed to updateMonthData() as it now allows you to optionally change the first day of the week if needed.

    • daySize property is no longer the Size class type with height and width values. It is now a DaySize enum with three options - Square, SeventhWidth and FreeForm. Please see the DaySize enum documentation to understand each value.

    • inDateStyle enum property has been removed as it is now redundant. The in-dates are present in each month data, you can choose to hide them on the view or keep them.

    • outDateStyle enum property is still available. However, there are now two options EndOfRow and EndOfGrid. The previously available third option None has been removed. You can simply hide the out-dates if you don't need them.

    • scrollMode enum property is now a boolean type named scrollPaged. Set this property to false to have the previous ScrollMode.CONTINUOUS scroll behavior or true to have the previous ScrollMode.PAGED behavior.

    • DayOwner enum has been renamed to DayPosition. The matching case values are:

      • DayOwner.PREVIOUS_MONTH => DayPosition.InDate
      • DayOwner.THIS_MONTH => DayPosition.MonthDate
      • DayOwner.NEXT_MONTH => DayPosition.OutDate
    • maxRowCount property has been removed as there is now a WeekCalendarView class that should be used if a week-based calendar is needed. The main CalendarView class is used for the month calendar implementation.

    • hasBoundaries property has been removed as it is no longer needed with the introduction of the week and month calendar implementations discussed above.

    • monthMarginStart | monthMarginTop | monthMarginEnd | monthMarginBottom properties have been merged into one monthMargins property.

    • monthPaddingStart | monthPaddingTop | monthPaddingEnd | monthPaddingBottom properties have been removed as they provided no real benefit. You can create a custom monthViewClass and set the paddings there if needed.

    Source code(tar.gz)
    Source code(zip)
    sample.apk(3.47 MB)
  • 1.1.0(Aug 29, 2022)

  • 1.0.4(May 9, 2021)

  • 1.0.3(Feb 27, 2021)

  • 1.0.2(Feb 14, 2021)

  • 1.0.1(Jan 2, 2021)

    • The method notifyCalendarChanged() no longer calls notifyDataSetChanged() internally but instead calls notifyItemRangeChanged() on all indices which is more efficient.
    • Some fixes in the example project.
    • Minor improvements.
    Source code(tar.gz)
    Source code(zip)
  • 1.0.0(Nov 8, 2020)

    • Remove deprecated fields and methods.
    • Remove month range update in the setup method. Calling this method multiple times will perform a full setup as expected. To update the start or end month, please use updateMonthRange() or updateMonthRangeAsync().
    Source code(tar.gz)
    Source code(zip)
    sample.apk(4.79 MB)
  • 0.4.5(Oct 11, 2020)

  • 0.4.4(Sep 19, 2020)

  • 0.4.3(Aug 16, 2020)

    • Fix: Calendar is not updated when dataset changes in some cases.
    • Fix: Month scroll listener is not called when scrollToDay() is used in paged calendar mode.
    Source code(tar.gz)
    Source code(zip)
  • 0.4.2(Jul 27, 2020)

  • 0.4.1(Jul 26, 2020)

    Note: This release introduced a regression which is fixed in version 0.4.2, please use 0.4.2 instead.

    • New methods and properties:

      • setMonthMargins() and setMonthPadding() for setting the month margins and padding all at once to minimize data regeneration.

      • updateMonthConfiguration() and updateMonthConfigurationAsync() for seting the inDateStyle, outDateStyle, maxRowCount and hasBoundaries all at once to minimize data regeneration.

      • setupAsync() for the asynchronous setup of the calendar with an optional completion callback. This supplements the already available setup() method.

      • updateMonthRangeAsync() for the asynchronous update of start and/or end month. This supplements the already available updateMonthRange() method.

      • daySize for setting the size, in pixels for each day cell view. Replaces the deprecated dayWidth and dayHeight properties.

    • Deprecated methods and properties:

      • dayWidth and dayHeight properties are deprecated, daySize should be used instead.

      • updateStartMonth() and updateEndMonth() methods are deprecated as they are just helper methods that only made the code more obscure especially with the introduction of a lot of similarly-named methods for async operations. Use updateMonthRange() instead.

      • Property setters for monthMarginStart, monthMarginEnd, monthMarginTop, monthMarginBottom, monthPaddingStart, monthPaddingEnd, monthPaddingTop, monthPaddingBottom are deprecated, please use the equivalent setter methods setMonthMargins() and setMonthPadding().

    • Some internal placeholder views and view groups previously used by the calendar to keep things in place have been removed. This means your calendar should now look really nice in the layout inspector (thanks @luis-cortes)

    • A lot of other internal optimizations.

    Many thanks to @luis-cortes for a lot of ideas and code contributions that went into this release.

    Source code(tar.gz)
    Source code(zip)
  • 0.4.0(Jul 11, 2020)

  • 0.3.5(Jun 11, 2020)

  • 0.3.4(Apr 11, 2020)

    • Fix: Wrong pagination logic when the Calendar size is larger than the month size.
    • Fix: Calendar height does not match the current month's height in vertical, paged mode.
    • Add cv_wrappedPageHeightAnimationDuration attribute for adjusting the duration of the animation used to change the CalendarView's height when needed. This is also available programmatically via the calendarView.wrappedPageHeightAnimationDuration property.
    Source code(tar.gz)
    Source code(zip)
  • 0.3.3(Apr 9, 2020)

  • 0.3.2(Jan 23, 2020)

  • 0.3.1(Dec 9, 2019)

    • Fix issue with smooth scrolling when scrollMode is paged.
    • Improve performance for unbounded month generation (thanks @evjava)
    • Decrease the minimum required SDK(minSdkVersion) to 15 (thanks @adilo)
    Source code(tar.gz)
    Source code(zip)
  • 0.3.0(Dec 7, 2019)

  • 0.2.9(Oct 28, 2019)

    • Add updateStartMonth, updateEndMonth and updateMonthRange methods for partial updates. (thanks @msimonides)
    • Optimize calendar setup logic.
    Source code(tar.gz)
    Source code(zip)
  • 0.2.8(Aug 28, 2019)

  • 0.2.7(Aug 25, 2019)

  • 0.2.6(Aug 10, 2019)

  • 0.2.5(Jul 31, 2019)

Owner
Kizito Nwose
Android and iOS software developer.
Kizito Nwose
Modern Calendar View Supporting Both Hijri and Gregorian Calendars but in highly dynamic way

KCalendar-View Modern calendar view supporting both Hijri and Gregorian calendar

Ahmed Ibrahim 8 Oct 29, 2022
A set of highly-opinionated, batteries-included gradle plugins to get you started building delicious multi-module Kotlin projects

Sourdough Gradle What is Sourdough Gradle? Sourdough is a set of highly opinionated gradle plugins that aim to act as the starter for your Kotlin proj

Backbone 0 Oct 3, 2022
Carousel Recyclerview let's you create carousel layout with the power of recyclerview by creating custom layout manager.

Carousel Recyclerview Create carousel effect in recyclerview with the CarouselRecyclerview in a simple way. Including in your project Gradle Add below

Jack and phantom 514 Jan 8, 2023
:blowfish: An Android & JVM key-value storage powered by Protobuf and Coroutines

PufferDB PufferDB is a ⚡ key-value storage powered by Protocol Buffers (aka Protobuf) and Coroutines. The purpose of this library is to provide an eff

Adriel Café 94 Dec 7, 2022
A libre smart powered comic book reader for Android.

Seeneva A libre smart powered comic book reader for Android. Translation: Русский • • Features • Speech balloons zooming • OCR and TTS • Performance •

Seeneva comic book reader 130 Jan 7, 2023
Beautifully designed Pokémon Database app for Android based on PokéAPI and powered by Kotlin.

PokéFacts PokéFacts is an open-source Pokémon Database app for Android based on PokéAPI and powered by Kotlin. The app allows users to view Pokémons,

Arjun Mehta 9 Oct 22, 2022
Type-safe time calculations in Kotlin, powered by generics.

Time This library is made for you if you have ever written something like this: val duration = 10 * 1000 to represent a duration of 10 seconds(in mill

Kizito Nwose 958 Dec 10, 2022
MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI

MangaKu ?? Introduction MangaKu App Powered by Kotlin Multiplatform Mobile, Jetpack Compose, and SwiftUI Module core: data and domain layer iosApp: io

Uwais Alqadri 132 Jan 8, 2023
On-device wake word detection powered by deep learning.

Porcupine Made in Vancouver, Canada by Picovoice Porcupine is a highly-accurate and lightweight wake word engine. It enables building always-listening

Picovoice 2.8k Dec 30, 2022
MyAndroidTools, but powered by Sui

MyAndroidTools 便捷地管理您的 Android 设备 简介 与另一款 MyAndroidTools 一样,本应用使你能够便捷地管理 Android 设备中的应用和组件。但与之不同的是,本应用通过 Sui 来调用高权限 API,所以不会在使用过程中频繁弹出 root 授权的 Toast

null 7 Sep 17, 2022
A discord bot made in Kotlin powered by JDA and Realms.

A discord bot made in Kotlin powered by JDA and Realms.

null 1 Jun 30, 2022
Android calendar library provides easy to use widget with events

Kotlin-AgendaCalendarView Kotlin-AgendaCalendarView based on AgendaCalendarView Kotlin-AgendaCalendarView is a awesome calendar widget with a list of

Ognev Zair 88 Nov 21, 2022
A beautiful material calendar with endless scroll, range selection and a lot more!

CrunchyCalendar A light, powerful and easy to use Calendar Widget with a number out of the box features: Infinite vertical scrolling in both direction

CleverPumpkin 483 Dec 25, 2022
Workout Journal is a mobile app based on Multi-Module and Clean Architecture for those who want to track their progress over a workout and a calendar period.

Workout-Journal Workout Journal is a mobile app for those who want to track their progress over a workout and a calendar period. The app allows you to

Maxim Smolyakov 4 Oct 23, 2022
YouTube Player library for Android and Chromecast, stable and customizable.

android-youtube-player android-youtube-player is a stable and customizable open source YouTube player for Android. It provides a simple View that can

Pierfrancesco Soffritti 2.9k Jan 2, 2023
RecyclerView Adapter Library with different models and different layouts as convenient as possible.

RecyclerView Presenter Convenience library to handle different view types with different presenters in a single RecyclerView. How to install repositor

Jan Rabe 86 Dec 26, 2022
:balloon: A lightweight popup like tooltips, fully customizable with an arrow and animations.

Balloon ?? A lightweight popup like tooltips, fully customizable with arrow and animations. Including in your project Gradle Add below codes to your r

Jaewoong Eum 2.9k Jan 9, 2023
An Easy-to-use Kotlin based Customizable Modules Collection with Material Layouts by BlackBeared.

Fusion By BlackBeared An Easy-to-use Kotlin based Customizable Library with Material Layouts by @blackbeared. Features Custom Floating Action Buttons

Sandip Savaliya 38 Oct 5, 2022
:balloon: A lightweight popup like tooltips, fully customizable with an arrow and animations.

Balloon ?? A lightweight popup like tooltips, fully customizable with arrow and animations. Including in your project Gradle Add below codes to your r

Jaewoong Eum 1.8k Apr 27, 2021