diff --git a/README.md b/README.md
index daccc1d..cd5527b 100644
--- a/README.md
+++ b/README.md
@@ -4,10 +4,20 @@
StickyTimeLine is timeline view for android.
-## What's New in 0.0.20? :tada:
-- change DotDrawable for each row of items[(#16)](https://github.com/sangcomz/StickyTimeLine/issues/16)
-- add java example[(#9)](https://github.com/sangcomz/StickyTimeLine/issues/9)
-- migrate to AndroidX
+## What's New in 0.1.0? :tada:
+- Add Horizontal Mode
+- Fix DEMO app
+- change attribute name
+ - `timeLineCircleColor` -> `timeLineDotColor`
+ - `timeLineCircleStrokeColor` -> `timeLineDotStrokeColor`
+
+ ## Result Screen
+
+ Feel free to send me a pull request with your app and I'll link you here:
+
+ | Sample
| AlleysMap
|
+ |:---------------------------------:|:--------------------------------:|
+ | ||
## How to Use
@@ -19,7 +29,7 @@ StickyTimeLine is timeline view for android.
dependencies {
//StickyTimeLine v0.0.20 and above only supports projects that have been migrated to androidx.
- compile 'com.github.sangcomz:StickyTimeLine:v0.0.20'
+ compile 'com.github.sangcomz:StickyTimeLine:v0.1.0'
}
```
### Usage
@@ -189,28 +199,20 @@ public class JavaExampleActivity extends AppCompatActivity {
#### attribute
-| Method Name | Description | Default Value |
-|:------------------------:|------------------------------------------------|:-------------:|
-| sectionBackgroundColor | To change section section background color | #f9f9f9 |
-| sectionTitleTextColor | To change section title color | #414fca |
-| sectionSubTitleTextColor | To change section sub title color | #d16767 |
-| timeLineColor | To change line color in timeline | #51ae45 |
-| timeLineCircleColor | To change circle color in timeline | #51ae45 |
-| timeLineCircleStrokeColor| To change circle stroke color in timeline | #f9f9f9 |
-| sectionTitleTextSize | To change section title text size | 14sp |
-| sectionSubTitleTextSize | To change section sub title text size | 12sp |
-| timeLineWidth | To change line width in timeline | 4dp |
-| isSticky | To change Sticky functionality in the Timeline | true |
-| customDotDrawable | To change the circle to custom drawable | null |
-
-## Result Screen
-
-Feel free to send me a pull request with your app and I'll link you here:
-
-| Project Name | Result Screen |
-|:---------:|---|
-| Sample
| |
-| AlleysMap
| |
+| Method Name | Description | Default Value |
+|:------------------------:|-------------------------------------------------------|:-------------:|
+| sectionBackgroundColor | To change section section background color | #f9f9f9 |
+| sectionTitleTextColor | To change section title color | #414fca |
+| sectionSubTitleTextColor | To change section sub title color | #d16767 |
+| timeLineColor | To change line color in timeline | #51ae45 |
+| timeLineDotColor | To change dot color in timeline | #51ae45 |
+| timeLineCircleStrokeColor| To change dot stroke color in timeline | #f9f9f9 |
+| sectionTitleTextSize | To change section title text size | 14sp |
+| sectionSubTitleTextSize | To change section sub title text size | 12sp |
+| timeLineWidth | To change line width in timeline | 4dp |
+| isSticky | To change Sticky functionality in the Timeline | true |
+| customDotDrawable | To change the circle to custom drawable | null |
+|sectionBackgroundColorMode| To change section background area(for horizontal mode)| MODE_FULL |
# Contribute
We welcome any contributions.
diff --git a/app/build.gradle b/app/build.gradle
index 6d49d8c..19f76f9 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -44,15 +44,15 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation "androidx.appcompat:appcompat:$support_version"
+ implementation "androidx.appcompat:appcompat:1.2.0"
implementation "androidx.constraintlayout:constraintlayout:$constraint_version"
- implementation "androidx.recyclerview:recyclerview:$support_version"
+ implementation "androidx.recyclerview:recyclerview:1.1.0"
implementation 'androidx.cardview:cardview:1.0.0'
implementation project(':stickytimelineview')
- implementation "androidx.appcompat:appcompat:$support_version"
- implementation 'androidx.constraintlayout:constraintlayout:1.1.3'
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test:runner:1.1.2-alpha02'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha02'
+ implementation "androidx.appcompat:appcompat:1.2.0"
+ implementation 'androidx.constraintlayout:constraintlayout:2.0.1'
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test:runner:1.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
diff --git a/app/src/main/java/xyz/sangcomz/stickytimeline/JavaExampleActivity.java b/app/src/main/java/xyz/sangcomz/stickytimeline/JavaExampleActivity.java
index e933a10..8ccddf9 100644
--- a/app/src/main/java/xyz/sangcomz/stickytimeline/JavaExampleActivity.java
+++ b/app/src/main/java/xyz/sangcomz/stickytimeline/JavaExampleActivity.java
@@ -3,16 +3,17 @@
import android.graphics.drawable.Drawable;
import android.os.Bundle;
-import org.jetbrains.annotations.Nullable;
-
-import java.util.List;
-
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.content.res.AppCompatResources;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
-import xyz.sangcomz.stickytimelineview.RecyclerSectionItemDecoration;
+
+import org.jetbrains.annotations.Nullable;
+
+import java.util.List;
+
import xyz.sangcomz.stickytimelineview.TimeLineRecyclerView;
+import xyz.sangcomz.stickytimelineview.callback.SectionCallback;
import xyz.sangcomz.stickytimelineview.model.SectionInfo;
public class JavaExampleActivity extends AppCompatActivity {
@@ -25,7 +26,7 @@ protected void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.activity_main);
initDrawable();
- TimeLineRecyclerView recyclerView = findViewById(R.id.recycler_view);
+ TimeLineRecyclerView recyclerView = findViewById(R.id.vertical_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(this,
RecyclerView.VERTICAL,
@@ -35,11 +36,11 @@ protected void onCreate(Bundle savedInstanceState) {
recyclerView.addItemDecoration(getSectionCallback(singerList));
- recyclerView.setAdapter(new SingerAdapter(getLayoutInflater(), singerList, R.layout.recycler_row));
+ recyclerView.setAdapter(new SingerAdapter(getLayoutInflater(), singerList, R.layout.recycler_vertical_row));
}
- private RecyclerSectionItemDecoration.SectionCallback getSectionCallback(final List singerList) {
- return new RecyclerSectionItemDecoration.SectionCallback() {
+ private SectionCallback getSectionCallback(final List singerList) {
+ return new SectionCallback() {
@Nullable
@Override
diff --git a/app/src/main/java/xyz/sangcomz/stickytimeline/MainActivity.kt b/app/src/main/java/xyz/sangcomz/stickytimeline/MainActivity.kt
index 752b35f..7eb36e6 100644
--- a/app/src/main/java/xyz/sangcomz/stickytimeline/MainActivity.kt
+++ b/app/src/main/java/xyz/sangcomz/stickytimeline/MainActivity.kt
@@ -6,8 +6,9 @@ import androidx.appcompat.app.AppCompatActivity
import androidx.appcompat.content.res.AppCompatResources
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
-import xyz.sangcomz.stickytimelineview.RecyclerSectionItemDecoration
-import xyz.sangcomz.stickytimelineview.TimeLineRecyclerView
+import kotlinx.android.synthetic.main.activity_main.*
+import xyz.sangcomz.stickytimelineview.callback.SectionCallback
+import xyz.sangcomz.stickytimelineview.decoration.VerticalSectionItemDecoration
import xyz.sangcomz.stickytimelineview.model.SectionInfo
class MainActivity : AppCompatActivity() {
@@ -28,32 +29,62 @@ class MainActivity : AppCompatActivity() {
AppCompatResources.getDrawable(this@MainActivity, R.drawable.ic_solo)
}
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
+ initVerticalRecyclerView()
+ initHorizontalRecyclerView()
+ }
- val recyclerView: TimeLineRecyclerView = findViewById(R.id.recycler_view)
+ private fun initVerticalRecyclerView() {
+ val singerList = getSingerList()
+ vertical_recycler_view.adapter = SingerAdapter(
+ layoutInflater,
+ singerList,
+ R.layout.recycler_vertical_row
+ )
//Currently only LinearLayoutManager is supported.
- recyclerView.layoutManager = LinearLayoutManager(
+ vertical_recycler_view.layoutManager = LinearLayoutManager(
this,
RecyclerView.VERTICAL,
false
)
- //Get data
- val singerList = getSingerList()
-
+ vertical_recycler_view.addItemDecoration(getSectionCallback(singerList))
+ }
- //Add RecyclerSectionItemDecoration.SectionCallback
- recyclerView.addItemDecoration(getSectionCallback(singerList))
+ private fun initHorizontalRecyclerView() {
+ val singerList = getSingerList()
+ horizontal_recycler_view.adapter = SingerAdapter(
+ layoutInflater,
+ singerList,
+ R.layout.recycler_horizontal_row
+ )
- //Set Adapter
- recyclerView.adapter = SingerAdapter(
+ horizontal_recycler_view2.adapter = SingerAdapter(
layoutInflater,
singerList,
- R.layout.recycler_row
+ R.layout.recycler_horizontal_row
+ )
+
+
+ //Currently only LinearLayoutManager is supported.
+ horizontal_recycler_view.layoutManager = LinearLayoutManager(
+ this,
+ RecyclerView.HORIZONTAL,
+ false
+ )
+
+ horizontal_recycler_view2.layoutManager = LinearLayoutManager(
+ this,
+ RecyclerView.HORIZONTAL,
+ false
)
+
+ horizontal_recycler_view.addItemDecoration(getSectionCallback(singerList))
+ horizontal_recycler_view2.addItemDecoration(getSectionCallback(singerList))
}
//Get data method
@@ -61,8 +92,8 @@ class MainActivity : AppCompatActivity() {
//Get SectionCallback method
- private fun getSectionCallback(singerList: List): RecyclerSectionItemDecoration.SectionCallback {
- return object : RecyclerSectionItemDecoration.SectionCallback {
+ private fun getSectionCallback(singerList: List): SectionCallback {
+ return object : SectionCallback {
//In your data, implement a method to determine if this is a section.
override fun isSection(position: Int): Boolean =
singerList[position].debuted != singerList[position - 1].debuted
diff --git a/app/src/main/java/xyz/sangcomz/stickytimeline/SingerRepo.kt b/app/src/main/java/xyz/sangcomz/stickytimeline/SingerRepo.kt
index cbc3386..77dd86e 100755
--- a/app/src/main/java/xyz/sangcomz/stickytimeline/SingerRepo.kt
+++ b/app/src/main/java/xyz/sangcomz/stickytimeline/SingerRepo.kt
@@ -11,23 +11,23 @@ class SingerRepo {
val singerList: List
get() {
val singerList = ArrayList()
- singerList.add(Singer("Solo", "1995.04", "Lim Chang Jung"))
+ singerList.add(Singer("Solo", "1995.04", "Lim ChangJung"))
singerList.add(Singer("FIN.K.L", "1998.05", "Lee Jin"))
- singerList.add(Singer("FIN.K.L", "1998.05", "Sung Yu Ri"))
- singerList.add(Singer("FIN.K.L", "1998.05", "Oak Joo Hyun"))
- singerList.add(Singer("FIN.K.L", "1998.05", "Lee Hyo Ri"))
+ singerList.add(Singer("FIN.K.L", "1998.05", "Sung YuRi"))
+ singerList.add(Singer("FIN.K.L", "1998.05", "Oak JooHyun"))
+ singerList.add(Singer("FIN.K.L", "1998.05", "Lee HyoRi"))
- singerList.add(Singer("Solo", "1999.04", "Kim Bumsoo"))
+ singerList.add(Singer("Solo", "1999.04", "Kim BumSoo"))
- singerList.add(Singer("Solo", "1999.11", "Park Hyo Shin"))
- singerList.add(Singer("Solo", "1999.11", "Lee Soo Young"))
- singerList.add(Singer("Solo", "2000.11", "Sung Si Kyung"))
+ singerList.add(Singer("Solo", "1999.11", "Park HyoShin"))
+ singerList.add(Singer("Solo", "1999.11", "Lee SooYoung"))
+ singerList.add(Singer("Solo", "2000.11", "Sung SiKyung"))
singerList.add(Singer("Buzz", "2003.10", "Kim Yeah"))
- singerList.add(Singer("Buzz", "2003.10", "Yun Woo Hyun"))
- singerList.add(Singer("Buzz", "2003.10", "Sin Jun Ki"))
- singerList.add(Singer("Buzz", "2003.10", "Min Kyung Hoon"))
+ singerList.add(Singer("Buzz", "2003.10", "Yun WooHyun"))
+ singerList.add(Singer("Buzz", "2003.10", "Sin JunKi"))
+ singerList.add(Singer("Buzz", "2003.10", "Min KyungHoon"))
singerList.add(Singer("Solo", "2006.06", "Yunha"))
@@ -42,17 +42,17 @@ class SingerRepo {
singerList.add(Singer("Wanna One", "2017.08", "Kang Daniel"))
singerList.add(Singer("Wanna One", "2017.08", "Lai Kuan Lin"))
- singerList.add(Singer("Wanna One", "2017.08", "Ong Seong Wu"))
- singerList.add(Singer("Wanna One", "2017.08", "Ha Sung Woon"))
- singerList.add(Singer("Wanna One", "2017.08", "Yoon Ji Sung"))
- singerList.add(Singer("Wanna One", "2017.08", "Park Woo Jin"))
- singerList.add(Singer("Wanna One", "2017.08", "Lee Dae Hwi"))
- singerList.add(Singer("Wanna One", "2017.08", "Kim Jae Hwan"))
- singerList.add(Singer("Wanna One", "2017.08", "Bae Jin Young"))
- singerList.add(Singer("Wanna One", "2017.08", "Hwang Min Hyun"))
- singerList.add(Singer("Wanna One", "2017.08", "Park Ji Hoon"))
-
- singerList.add(Singer("Solo", "2017.11", "Woo Won Jae"))
+ singerList.add(Singer("Wanna One", "2017.08", "Ong SeongWu"))
+ singerList.add(Singer("Wanna One", "2017.08", "Ha SungWoon"))
+ singerList.add(Singer("Wanna One", "2017.08", "Yoon JiSung"))
+ singerList.add(Singer("Wanna One", "2017.08", "Park WooJin"))
+ singerList.add(Singer("Wanna One", "2017.08", "Lee DaeHwi"))
+ singerList.add(Singer("Wanna One", "2017.08", "Kim JaeHwan"))
+ singerList.add(Singer("Wanna One", "2017.08", "Bae JinYoung"))
+ singerList.add(Singer("Wanna One", "2017.08", "Hwang MinHyun"))
+ singerList.add(Singer("Wanna One", "2017.08", "Park JiHoon"))
+
+ singerList.add(Singer("Solo", "2017.11", "Woo WonJae"))
return singerList
}
diff --git a/app/src/main/res/drawable/ic_solo.xml b/app/src/main/res/drawable/ic_solo.xml
index cb10b5f..0341836 100644
--- a/app/src/main/res/drawable/ic_solo.xml
+++ b/app/src/main/res/drawable/ic_solo.xml
@@ -1,7 +1,14 @@
-
-
+
-
+ android:strokeWidth="10"
+ android:strokeColor="#F9F9F9" />
+
diff --git a/app/src/main/res/layout/activity_main.xml b/app/src/main/res/layout/activity_main.xml
index 475f2c1..7c7dd4f 100644
--- a/app/src/main/res/layout/activity_main.xml
+++ b/app/src/main/res/layout/activity_main.xml
@@ -6,9 +6,92 @@
android:layout_height="match_parent"
tools:context="xyz.sangcomz.stickytimeline.MainActivity">
+
+
+
+
+
+
+
+
+ android:background="#3F51B5"
+ android:paddingStart="8dp"
+ android:paddingTop="16dp"
+ android:paddingEnd="8dp"
+ android:paddingBottom="16dp"
+ android:text="HORIZONTAL"
+ android:textColor="#ffffff"
+ android:textSize="24dp"
+ android:textStyle="bold"
+ app:layout_constraintEnd_toEndOf="parent"
+ app:layout_constraintStart_toStartOf="parent"
+ app:layout_constraintTop_toBottomOf="@id/guideline" />
+
+
+
+
+
diff --git a/app/src/main/res/layout/recycler_horizontal_row.xml b/app/src/main/res/layout/recycler_horizontal_row.xml
new file mode 100755
index 0000000..45b8372
--- /dev/null
+++ b/app/src/main/res/layout/recycler_horizontal_row.xml
@@ -0,0 +1,14 @@
+
+
+
+
+
+
diff --git a/app/src/main/res/layout/recycler_row.xml b/app/src/main/res/layout/recycler_vertical_row.xml
similarity index 100%
rename from app/src/main/res/layout/recycler_row.xml
rename to app/src/main/res/layout/recycler_vertical_row.xml
diff --git a/build.gradle b/build.gradle
index cf3d4bc..dab7543 100644
--- a/build.gradle
+++ b/build.gradle
@@ -3,9 +3,8 @@
buildscript {
ext {
- support_version = '1.1.0-alpha03'
- kotlin_version = '1.3.21'
- constraint_version = '1.1.3'
+ kotlin_version = '1.3.72'
+ constraint_version = '2.0.1'
}
repositories {
@@ -13,7 +12,7 @@ buildscript {
jcenter()
}
dependencies {
- classpath 'com.android.tools.build:gradle:3.3.2'
+ classpath 'com.android.tools.build:gradle:4.0.1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath 'com.github.dcendents:android-maven-gradle-plugin:2.1'
// NOTE: Do not place your application dependencies here; they belong
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index 5493714..2f36f39 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
-#Sun Mar 10 16:44:37 KST 2019
+#Mon Aug 10 23:14:19 KST 2020
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-4.10.1-all.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.1.1-all.zip
diff --git a/pic/sample_result.gif b/pic/sample_result.gif
index 53829f1..5b6d1d7 100644
Binary files a/pic/sample_result.gif and b/pic/sample_result.gif differ
diff --git a/settings.gradle b/settings.gradle
index 1e64947..a021b50 100644
--- a/settings.gradle
+++ b/settings.gradle
@@ -1,7 +1,7 @@
include ':app', ':stickytimelineview'
-gradle.ext.set('versionCode', 6)
-gradle.ext.set('versionName', '0.0.20')
+gradle.ext.set('versionCode', 8)
+gradle.ext.set('versionName', '0.1.0')
gradle.ext.set('minSdk', 16)
gradle.ext.set('targetSdk', 28)
diff --git a/stickytimelineview/build.gradle b/stickytimelineview/build.gradle
index 1c07a08..769e61b 100644
--- a/stickytimelineview/build.gradle
+++ b/stickytimelineview/build.gradle
@@ -31,12 +31,12 @@ android {
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
- implementation 'androidx.appcompat:appcompat:1.1.0-alpha03'
- compile 'androidx.recyclerview:recyclerview:1.1.0-alpha03'
+ implementation 'androidx.appcompat:appcompat:1.2.0'
+ compile 'androidx.recyclerview:recyclerview:1.1.0'
compile "androidx.constraintlayout:constraintlayout:$constraint_version"
- testImplementation 'junit:junit:4.12'
- androidTestImplementation 'androidx.test:runner:1.1.2-alpha02'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0-alpha02'
+ testImplementation 'junit:junit:4.13'
+ androidTestImplementation 'androidx.test:runner:1.3.0'
+ androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
}
diff --git a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/TimeLineRecyclerView.kt b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/TimeLineRecyclerView.kt
index a359774..e3b22c5 100644
--- a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/TimeLineRecyclerView.kt
+++ b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/TimeLineRecyclerView.kt
@@ -4,6 +4,9 @@ import android.content.Context
import android.util.AttributeSet
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.RecyclerView
+import xyz.sangcomz.stickytimelineview.callback.SectionCallback
+import xyz.sangcomz.stickytimelineview.decoration.HorizontalSectionItemDecoration
+import xyz.sangcomz.stickytimelineview.decoration.VerticalSectionItemDecoration
import xyz.sangcomz.stickytimelineview.model.RecyclerViewAttr
@@ -27,50 +30,110 @@ class TimeLineRecyclerView(context: Context, attrs: AttributeSet?) : RecyclerVie
private var recyclerViewAttr: RecyclerViewAttr? = null
+ companion object {
+ private const val MODE_VERTICAL = 0x00
+ private const val MODE_HORIZONTAL = 0x01
+
+ const val MODE_FULL = 0x00
+ const val MODE_TO_TIME_LINE = 0x01
+ const val MODE_TO_DOT = 0x02
+ }
+
init {
attrs?.let {
- val a = context?.theme?.obtainStyledAttributes(
- attrs,
- R.styleable.TimeLineRecyclerView,
- 0, 0)
+ val a = context.theme?.obtainStyledAttributes(
+ attrs,
+ R.styleable.TimeLineRecyclerView,
+ 0, 0
+ )
a?.let {
recyclerViewAttr =
- RecyclerViewAttr(it.getColor(R.styleable.TimeLineRecyclerView_sectionBackgroundColor,
- ContextCompat.getColor(context, R.color.colorDefaultBackground)),
- it.getColor(R.styleable.TimeLineRecyclerView_sectionTitleTextColor,
- ContextCompat.getColor(context, R.color.colorDefaultTitle)),
- it.getColor(R.styleable.TimeLineRecyclerView_sectionSubTitleTextColor,
- ContextCompat.getColor(context, R.color.colorDefaultSubTitle)),
- it.getColor(R.styleable.TimeLineRecyclerView_timeLineColor,
- ContextCompat.getColor(context, R.color.colorDefaultTitle)),
- it.getColor(R.styleable.TimeLineRecyclerView_timeLineCircleColor,
- ContextCompat.getColor(context, R.color.colorDefaultTitle)),
- it.getColor(R.styleable.TimeLineRecyclerView_timeLineCircleStrokeColor,
- ContextCompat.getColor(context, R.color.colorDefaultStroke)),
- it.getDimension(R.styleable.TimeLineRecyclerView_sectionTitleTextSize,
- context.resources.getDimension(R.dimen.title_text_size)),
- it.getDimension(R.styleable.TimeLineRecyclerView_sectionSubTitleTextSize,
- context.resources.getDimension(R.dimen.sub_title_text_size)),
- it.getDimension(R.styleable.TimeLineRecyclerView_timeLineWidth,
- context.resources.getDimension(R.dimen.line_width)),
- it.getBoolean(R.styleable.TimeLineRecyclerView_isSticky, true),
- it.getDrawable(R.styleable.TimeLineRecyclerView_customDotDrawable))
+ RecyclerViewAttr(
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_sectionBackgroundColor,
+ ContextCompat.getColor(context, R.color.colorDefaultBackground)
+ ),
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_sectionTitleTextColor,
+ ContextCompat.getColor(context, R.color.colorDefaultTitle)
+ ),
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_sectionSubTitleTextColor,
+ ContextCompat.getColor(context, R.color.colorDefaultSubTitle)
+ ),
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_timeLineColor,
+ ContextCompat.getColor(context, R.color.colorDefaultTitle)
+ ),
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_timeLineDotColor,
+ ContextCompat.getColor(context, R.color.colorDefaultTitle)
+ ),
+ it.getColor(
+ R.styleable.TimeLineRecyclerView_timeLineDotStrokeColor,
+ ContextCompat.getColor(context, R.color.colorDefaultStroke)
+ ),
+ it.getDimension(
+ R.styleable.TimeLineRecyclerView_sectionTitleTextSize,
+ context.resources.getDimension(R.dimen.title_text_size)
+ ),
+ it.getDimension(
+ R.styleable.TimeLineRecyclerView_sectionSubTitleTextSize,
+ context.resources.getDimension(R.dimen.sub_title_text_size)
+ ),
+ it.getDimension(
+ R.styleable.TimeLineRecyclerView_timeLineWidth,
+ context.resources.getDimension(R.dimen.line_width)
+ ),
+ it.getBoolean(R.styleable.TimeLineRecyclerView_isSticky, true),
+ it.getDrawable(R.styleable.TimeLineRecyclerView_customDotDrawable),
+ it.getInt(R.styleable.TimeLineRecyclerView_timeLineMode, MODE_VERTICAL),
+ it.getInt(
+ R.styleable.TimeLineRecyclerView_sectionBackgroundColorMode,
+ MODE_FULL
+ )
+ )
}
+ a?.recycle()
}
}
/**
- * Add RecyclerSectionItemDecoration for Sticky TimeLineView
+ * Add VerticalSectionItemDecoration for Sticky TimeLineView
*
* @param callback SectionCallback
+ * if you'd like to know more mode , look at res/values/attrs.xml
*/
- fun addItemDecoration(callback: RecyclerSectionItemDecoration.SectionCallback) {
+ fun addItemDecoration(callback: SectionCallback) {
recyclerViewAttr?.let {
- this.addItemDecoration(RecyclerSectionItemDecoration(context,
- callback,
- it))
+ val decoration: ItemDecoration =
+ when (it.timeLineMode) {
+ MODE_VERTICAL -> {
+ VerticalSectionItemDecoration(
+ context,
+ callback,
+ it
+ )
+ }
+ MODE_HORIZONTAL -> {
+ HorizontalSectionItemDecoration(
+ context,
+ callback,
+ it
+ )
+ }
+ else -> {
+ VerticalSectionItemDecoration(
+ context,
+ callback,
+ it
+ )
+ }
+ }
+
+ this.addItemDecoration(decoration)
}
}
}
\ No newline at end of file
diff --git a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/callback/SectionCallback.kt b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/callback/SectionCallback.kt
new file mode 100644
index 0000000..a170ebf
--- /dev/null
+++ b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/callback/SectionCallback.kt
@@ -0,0 +1,15 @@
+package xyz.sangcomz.stickytimelineview.callback
+
+import xyz.sangcomz.stickytimelineview.model.SectionInfo
+
+interface SectionCallback {
+ /**
+ * To check if section is
+ */
+ fun isSection(position: Int): Boolean
+
+ /**
+ * Functions that return a section header in a section
+ */
+ fun getSectionHeader(position: Int): SectionInfo?
+}
\ No newline at end of file
diff --git a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/HorizontalSectionItemDecoration.kt b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/HorizontalSectionItemDecoration.kt
new file mode 100644
index 0000000..9740bcd
--- /dev/null
+++ b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/HorizontalSectionItemDecoration.kt
@@ -0,0 +1,275 @@
+package xyz.sangcomz.stickytimelineview.decoration
+
+import android.content.Context
+import android.graphics.Canvas
+import android.graphics.Paint
+import android.graphics.Rect
+import android.graphics.Typeface
+import android.graphics.drawable.Drawable
+import android.graphics.drawable.GradientDrawable
+import android.view.View
+import androidx.recyclerview.widget.RecyclerView
+import xyz.sangcomz.stickytimelineview.TimeLineRecyclerView.Companion.MODE_TO_DOT
+import xyz.sangcomz.stickytimelineview.TimeLineRecyclerView.Companion.MODE_TO_TIME_LINE
+import xyz.sangcomz.stickytimelineview.callback.SectionCallback
+import xyz.sangcomz.stickytimelineview.ext.DP
+import xyz.sangcomz.stickytimelineview.model.RecyclerViewAttr
+import xyz.sangcomz.stickytimelineview.model.SectionInfo
+
+class HorizontalSectionItemDecoration(
+ context: Context,
+ private val sectionCallback: SectionCallback,
+ private val recyclerViewAttr: RecyclerViewAttr
+) : RecyclerView.ItemDecoration() {
+
+ private var defaultOffset: Int = 8.DP(context).toInt()
+
+ private val headerSectionBackgroundPaint = Paint().apply {
+ isAntiAlias = true
+ color = recyclerViewAttr.sectionBackgroundColor
+ }
+
+ private val linePaint = Paint().apply {
+ isAntiAlias = true
+ color = recyclerViewAttr.sectionLineColor
+ strokeWidth = recyclerViewAttr.sectionLineWidth
+ }
+
+ private val headerTitlePaint = Paint().apply {
+ isAntiAlias = true
+ textSize = recyclerViewAttr.sectionTitleTextSize
+ color = recyclerViewAttr.sectionTitleTextColor
+ typeface = Typeface.create(FONT_FAMILY, Typeface.BOLD)
+ }
+
+ private val headerSubTitlePaint = Paint().apply {
+ isAntiAlias = true
+ textSize = recyclerViewAttr.sectionSubTitleTextSize
+ color = recyclerViewAttr.sectionSubTitleTextColor
+ typeface = Typeface.create(FONT_FAMILY, Typeface.NORMAL)
+ }
+
+ override fun getItemOffsets(
+ outRect: Rect,
+ view: View,
+ parent: RecyclerView,
+ state: RecyclerView.State
+ ) {
+ super.getItemOffsets(
+ outRect,
+ view,
+ parent,
+ state
+ )
+ outRect.top = getTopSpace().toInt()
+
+ val leftMargin = defaultOffset
+ val rightMargin = defaultOffset
+
+ outRect.bottom = defaultOffset / 2
+ outRect.left = leftMargin
+ outRect.right = rightMargin
+ }
+
+
+ override fun onDrawOver(canvas: Canvas, parent: RecyclerView, state: RecyclerView.State) {
+ super.onDrawOver(canvas, parent, state)
+
+ drawBackground(canvas, parent)
+ drawLine(canvas, parent)
+
+ var previousHeader: SectionInfo? = null
+
+ if (recyclerViewAttr.isSticky) {
+ val topChild = parent.getChildAt(0)
+ val topHeaderSectionInfo = getCurrentTopSectionInfo(parent) ?: return
+
+ val currentHeaderWidth = getCurrentHeaderViewWidth(parent)
+ val nextHeaderView = getNextHeaderView(parent)
+
+ val isContact =
+ nextHeaderView?.left in 0..currentHeaderWidth.toInt() + defaultOffset * 2
+ val defaultLeftOffset = -(topChild.left).toFloat() + defaultOffset
+
+ previousHeader = topHeaderSectionInfo
+
+ if (isContact) {
+ val offset = currentHeaderWidth - ((nextHeaderView?.left ?: 0) - defaultOffset * 2)
+
+ drawHeader(
+ canvas,
+ topChild,
+ topHeaderSectionInfo,
+ defaultLeftOffset - offset
+ )
+ } else {
+ drawHeader(
+ canvas,
+ topChild,
+ topHeaderSectionInfo,
+ defaultLeftOffset
+ )
+ }
+ }
+
+ for (i in 0 until parent.childCount) {
+ val child = parent.getChildAt(i)
+ val position = parent.getChildAdapterPosition(child)
+
+ sectionCallback.getSectionHeader(position)?.let { sectionInfo ->
+ if (previousHeader?.title != sectionInfo.title) {
+ if (getIsSection(position)) {
+ drawHeader(canvas, child, sectionInfo)
+ }
+ previousHeader = sectionInfo
+ }
+ }
+ }
+ }
+
+ /**
+ * Draw a line in the timeline.
+ */
+ private fun drawLine(canvas: Canvas, parent: RecyclerView) {
+ val yValue = getTopSpace() - (defaultOffset * 2) - (defaultOffset / 4)
+
+ canvas.drawLines(floatArrayOf(0f, yValue, parent.width.toFloat(), yValue), linePaint)
+ }
+
+ private fun drawBackground(canvas: Canvas, parent: RecyclerView) {
+ var bottom = getTopSpace() - defaultOffset
+
+ when (recyclerViewAttr.sectionBackgroundColorMode) {
+ MODE_TO_DOT -> {
+ bottom -= (defaultOffset * 2 + defaultOffset / 2)
+ }
+ MODE_TO_TIME_LINE -> {
+ bottom -= if (recyclerViewAttr.sectionLineWidth > defaultOffset * 2 + defaultOffset / 2) {
+ recyclerViewAttr.sectionLineWidth / 2
+ } else {
+ (defaultOffset + defaultOffset / 4) - (recyclerViewAttr.sectionLineWidth / 2)
+ }
+ }
+ }
+
+ val rect = Rect(parent.left, 0, parent.width, bottom.toInt())
+
+ canvas.drawRect(rect, headerSectionBackgroundPaint)
+ }
+
+ /**
+ * Returns the oval dotDrawable of the timeline.
+ */
+ private fun getOvalDrawable(): Drawable {
+ val strokeWidth = defaultOffset / 2
+ val roundRadius = defaultOffset * 2
+ val strokeColor = recyclerViewAttr.sectionDotStrokeColor
+ val fillColor = recyclerViewAttr.sectionDotColor
+
+ val gd = GradientDrawable()
+ gd.setColor(fillColor)
+ gd.cornerRadius = roundRadius.toFloat()
+ gd.setStroke(strokeWidth, strokeColor)
+
+ return gd
+ }
+
+ /**
+ * Draw a header
+ */
+ private fun drawHeader(c: Canvas, child: View, sectionInfo: SectionInfo, offset: Float = 0f) {
+ c.save()
+ c.translate((child.left).toFloat() + offset, 0f)
+ drawDotDrawable(c, sectionInfo)
+ drawHeaderTitle(c, sectionInfo)
+ drawHeaderSubTitle(c, sectionInfo)
+ c.restore()
+ }
+
+ private fun drawDotDrawable(canvas: Canvas, sectionInfo: SectionInfo) {
+ val dotDrawable =
+ sectionInfo.dotDrawable ?: recyclerViewAttr.customDotDrawable ?: getOvalDrawable()
+ canvas.save()
+ canvas.translate(
+ 0f,
+ recyclerViewAttr.sectionTitleTextSize + recyclerViewAttr.sectionSubTitleTextSize + defaultOffset
+ )
+ dotDrawable.draw(canvas)
+ canvas.restore()
+ }
+
+ private fun drawHeaderTitle(canvas: Canvas, sectionInfo: SectionInfo) {
+ val subTitleHeight =
+ if (sectionInfo.subTitle.isNullOrEmpty()) recyclerViewAttr.sectionSubTitleTextSize else 0f
+ canvas.drawText(
+ sectionInfo.title,
+ 0f,
+ recyclerViewAttr.sectionTitleTextSize - subTitleHeight, headerTitlePaint
+ )
+ }
+
+ private fun drawHeaderSubTitle(canvas: Canvas, sectionInfo: SectionInfo) {
+ val subTitle = sectionInfo.subTitle ?: return
+ canvas.drawText(
+ subTitle,
+ 0f,
+ recyclerViewAttr.sectionTitleTextSize + recyclerViewAttr.sectionSubTitleTextSize,
+ headerSubTitlePaint
+ )
+ }
+
+ private fun getCurrentHeaderViewWidth(parent: RecyclerView): Float {
+ val prevHeaderSectionInfo = getCurrentTopSectionInfo(parent) ?: return 0f
+
+ val titleWidth = headerTitlePaint.measureText(prevHeaderSectionInfo.title)
+ val subTitleWidth = headerSubTitlePaint.measureText(prevHeaderSectionInfo.subTitle ?: "")
+ return titleWidth.coerceAtLeast(subTitleWidth)
+ }
+
+ private fun getIsSection(position: Int): Boolean = when (position) {
+ 0 -> {
+ true
+ }
+ -1 -> {
+ false
+ }
+ else -> {
+ sectionCallback.isSection(position)
+ }
+ }
+
+ private fun getTopSpace(): Float {
+ return recyclerViewAttr.sectionTitleTextSize +
+ recyclerViewAttr.sectionSubTitleTextSize +
+ (defaultOffset * 4) +
+ (defaultOffset / 2)
+ }
+
+ private fun getCurrentTopSectionInfo(parent: RecyclerView): SectionInfo? {
+ return parent.getChildAt(0)
+ ?.let { sectionCallback.getSectionHeader(parent.getChildAdapterPosition(it)) }
+ }
+
+ private fun getNextHeaderView(parent: RecyclerView): View? {
+ val currentTopSectionInfo = getCurrentTopSectionInfo(parent)
+
+ return (0 until parent.childCount)
+ .map {
+ parent.getChildAt(it)
+ }
+ .firstOrNull {
+ sectionCallback.getSectionHeader(parent.getChildAdapterPosition(it)) != currentTopSectionInfo
+ }
+ }
+
+ private fun getDotRadius() = defaultOffset + defaultOffset / 4
+
+
+ private fun isLineBiggerThenDot(): Boolean {
+ return recyclerViewAttr.sectionLineWidth > (getDotRadius() * 2)
+ }
+
+ companion object {
+ private const val FONT_FAMILY = "sans-serif-light"
+ }
+}
\ No newline at end of file
diff --git a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/RecyclerSectionItemDecoration.kt b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/VerticalSectionItemDecoration.kt
similarity index 91%
rename from stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/RecyclerSectionItemDecoration.kt
rename to stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/VerticalSectionItemDecoration.kt
index c71c407..b7354b7 100755
--- a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/RecyclerSectionItemDecoration.kt
+++ b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/decoration/VerticalSectionItemDecoration.kt
@@ -1,4 +1,4 @@
-package xyz.sangcomz.stickytimelineview
+package xyz.sangcomz.stickytimelineview.decoration
import android.content.Context
import android.graphics.Canvas
@@ -13,6 +13,8 @@ import android.view.ViewGroup
import android.widget.TextView
import androidx.appcompat.widget.AppCompatImageView
import androidx.recyclerview.widget.RecyclerView
+import xyz.sangcomz.stickytimelineview.R
+import xyz.sangcomz.stickytimelineview.callback.SectionCallback
import xyz.sangcomz.stickytimelineview.ext.DP
import xyz.sangcomz.stickytimelineview.model.RecyclerViewAttr
import xyz.sangcomz.stickytimelineview.model.SectionInfo
@@ -27,7 +29,7 @@ import xyz.sangcomz.stickytimelineview.model.SectionInfo
* I was inspired by his code. And I used some of his code in the library.
* https://github.com/paetztm/recycler_view_headers
*/
-class RecyclerSectionItemDecoration(
+class VerticalSectionItemDecoration(
context: Context,
private val sectionCallback: SectionCallback,
private val recyclerViewAttr: RecyclerViewAttr
@@ -141,7 +143,7 @@ class RecyclerSectionItemDecoration(
private fun getHeaderView(parent: RecyclerView) {
headerView = inflateHeaderView(parent)
headerView?.let { headerView ->
- headerBackground = headerView.findViewById(R.id.v_item_background)
+ headerBackground = headerView.findViewById(R.id.lin_item_background)
headerTitle = headerView.findViewById(R.id.list_item_section_title)
headerSubTitle = headerView.findViewById(R.id.list_item_section_sub_title)
dot = headerView.findViewById(R.id.dot)
@@ -207,9 +209,6 @@ class RecyclerSectionItemDecoration(
)
}
- /**
- *
- */
private fun getChildInContact(parent: RecyclerView, contactPoint: Int): View? =
(0 until parent.childCount)
.map {
@@ -225,8 +224,8 @@ class RecyclerSectionItemDecoration(
private fun getOvalDrawable(): Drawable {
val strokeWidth = defaultOffset / 2
val roundRadius = defaultOffset * 2
- val strokeColor = recyclerViewAttr.sectionStrokeColor
- val fillColor = recyclerViewAttr.sectionCircleColor
+ val strokeColor = recyclerViewAttr.sectionDotStrokeColor
+ val fillColor = recyclerViewAttr.sectionDotStrokeColor
val gd = GradientDrawable()
gd.setColor(fillColor)
@@ -253,18 +252,9 @@ class RecyclerSectionItemDecoration(
private fun drawHeader(c: Canvas, child: View, headerView: View) {
c.save()
if (recyclerViewAttr.isSticky) {
- c.translate(
- 0f,
- Math.max(
- 0,
- child.top - headerView.height
- ).toFloat()
- )
+ c.translate(0f, 0.coerceAtLeast(child.top - headerView.height).toFloat())
} else {
- c.translate(
- 0f,
- (child.top - headerView.height).toFloat()
- )
+ c.translate(0f, (child.top - headerView.height).toFloat())
}
headerView.draw(c)
c.restore()
@@ -332,22 +322,6 @@ class RecyclerSectionItemDecoration(
}
}
-
-
- /**
- * Section-specific callback interface
- */
- interface SectionCallback {
- /**
- * To check if section is
- */
- fun isSection(position: Int): Boolean
-
- /**
- * Functions that return a section header in a section
- */
- fun getSectionHeader(position: Int): SectionInfo?
- }
}
diff --git a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/model/RecyclerViewAttr.kt b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/model/RecyclerViewAttr.kt
index a8807ba..70441e2 100644
--- a/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/model/RecyclerViewAttr.kt
+++ b/stickytimelineview/src/main/java/xyz/sangcomz/stickytimelineview/model/RecyclerViewAttr.kt
@@ -5,15 +5,18 @@ import android.graphics.drawable.Drawable
/**
* Created by seokwon.jeong on 17/11/2017.
*/
-data class RecyclerViewAttr(val sectionBackgroundColor: Int,
- val sectionTitleTextColor: Int,
- val sectionSubTitleTextColor: Int,
- val sectionLineColor: Int,
- val sectionCircleColor: Int,
- val sectionStrokeColor: Int,
- val sectionTitleTextSize: Float,
- val sectionSubTitleTextSize: Float,
- val sectionLineWidth: Float,
- val isSticky: Boolean,
- val customDotDrawable: Drawable?
+data class RecyclerViewAttr(
+ val sectionBackgroundColor: Int,
+ val sectionTitleTextColor: Int,
+ val sectionSubTitleTextColor: Int,
+ val sectionLineColor: Int,
+ val sectionDotColor: Int,
+ val sectionDotStrokeColor: Int,
+ val sectionTitleTextSize: Float,
+ val sectionSubTitleTextSize: Float,
+ val sectionLineWidth: Float,
+ val isSticky: Boolean,
+ val customDotDrawable: Drawable?,
+ val timeLineMode: Int,
+ val sectionBackgroundColorMode: Int
)
\ No newline at end of file
diff --git a/stickytimelineview/src/main/res/layout/recycler_section_header.xml b/stickytimelineview/src/main/res/layout/recycler_section_header.xml
index 9cc40bd..5f674b6 100755
--- a/stickytimelineview/src/main/res/layout/recycler_section_header.xml
+++ b/stickytimelineview/src/main/res/layout/recycler_section_header.xml
@@ -1,7 +1,6 @@
@@ -10,18 +9,20 @@
android:id="@+id/dot"
android:layout_width="@dimen/dot_size"
android:layout_height="@dimen/dot_size"
- android:layout_marginRight="2dp"
android:layout_marginLeft="2dp"
+ android:layout_marginRight="2dp"
app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toStartOf="@+id/v_item_background"
+ app:layout_constraintEnd_toStartOf="@+id/lin_item_background"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
-
+ app:layout_constraintStart_toStartOf="@+id/lin_item_background"
+ app:layout_constraintTop_toTopOf="@+id/dot" />
+ app:layout_constraintTop_toBottomOf="@+id/list_item_section_title" />
diff --git a/stickytimelineview/src/main/res/values/attrs.xml b/stickytimelineview/src/main/res/values/attrs.xml
index ca4c5cc..c1aaa32 100644
--- a/stickytimelineview/src/main/res/values/attrs.xml
+++ b/stickytimelineview/src/main/res/values/attrs.xml
@@ -1,18 +1,30 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
+
+
\ No newline at end of file