diff --git a/.idea/gradle.xml b/.idea/gradle.xml index 6c252ba..0b0a983 100644 --- a/.idea/gradle.xml +++ b/.idea/gradle.xml @@ -13,6 +13,7 @@ diff --git a/app/build.gradle b/app/build.gradle index d8e97ed..0fceb54 100644 --- a/app/build.gradle +++ b/app/build.gradle @@ -32,6 +32,7 @@ android { implementation fileTree(dir: 'libs', include: ['*.jar']) implementation project(':design_system') implementation project(':rally_pie') + implementation project(':rally_scrollable_tab') implementation project(':rally_line_chart') implementation project(':rally_line_indicator') implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" diff --git a/app/src/main/java/io/material/rally/ui/detail/DetailActivity.kt b/app/src/main/java/io/material/rally/ui/detail/DetailActivity.kt index e9e2c0a..4236eda 100644 --- a/app/src/main/java/io/material/rally/ui/detail/DetailActivity.kt +++ b/app/src/main/java/io/material/rally/ui/detail/DetailActivity.kt @@ -3,11 +3,23 @@ package io.material.rally.ui.detail import androidx.appcompat.app.AppCompatActivity import android.os.Bundle import io.material.rally.R +import kotlinx.android.synthetic.main.activity_detail.tab class DetailActivity : AppCompatActivity() { override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_detail) + + setUpTab() + } + + private fun setUpTab() { + tab.addTabs( + listOf( + "OverView", "Jan 2018", "Jan 2018", "Jan 2018", "Jan 2018", "Jan 2018", "Jan 2018", + "Jan 2018" + ) + ) } } diff --git a/app/src/main/res/layout/activity_detail.xml b/app/src/main/res/layout/activity_detail.xml index 0e4deb4..7bcc55e 100644 --- a/app/src/main/res/layout/activity_detail.xml +++ b/app/src/main/res/layout/activity_detail.xml @@ -1,5 +1,5 @@ - - \ No newline at end of file + + + \ No newline at end of file diff --git a/design_system/src/main/res/values/type.xml b/design_system/src/main/res/values/type.xml index ad9e52c..83a1427 100644 --- a/design_system/src/main/res/values/type.xml +++ b/design_system/src/main/res/values/type.xml @@ -106,4 +106,8 @@ 10sp + + diff --git a/rally_scrollable_tab/.gitignore b/rally_scrollable_tab/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/rally_scrollable_tab/.gitignore @@ -0,0 +1 @@ +/build diff --git a/rally_scrollable_tab/build.gradle b/rally_scrollable_tab/build.gradle new file mode 100644 index 0000000..df1bb76 --- /dev/null +++ b/rally_scrollable_tab/build.gradle @@ -0,0 +1,35 @@ +apply plugin: 'com.android.library' +apply plugin: 'kotlin-android' +apply plugin: 'kotlin-android-extensions' + +android { + compileSdkVersion 29 + buildToolsVersion "29.0.1" + + defaultConfig { + minSdkVersion 19 + targetSdkVersion 29 + versionCode 1 + versionName "1.0" + + testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" + } + + buildTypes { + release { + minifyEnabled false + proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' + } + } +} + +dependencies { + implementation fileTree(dir: 'libs', include: ['*.jar']) + + implementation 'androidx.appcompat:appcompat:1.0.2' + implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version" + testImplementation 'junit:junit:4.12' + androidTestImplementation 'androidx.test:runner:1.2.0' + androidTestImplementation 'androidx.test.espresso:espresso-core:3.2.0' + implementation 'androidx.recyclerview:recyclerview:1.0.0' +} diff --git a/rally_scrollable_tab/proguard-rules.pro b/rally_scrollable_tab/proguard-rules.pro new file mode 100644 index 0000000..f1b4245 --- /dev/null +++ b/rally_scrollable_tab/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile diff --git a/rally_scrollable_tab/src/androidTest/java/com/example/rally_scrollable_tab/ExampleInstrumentedTest.java b/rally_scrollable_tab/src/androidTest/java/com/example/rally_scrollable_tab/ExampleInstrumentedTest.java new file mode 100644 index 0000000..da35d52 --- /dev/null +++ b/rally_scrollable_tab/src/androidTest/java/com/example/rally_scrollable_tab/ExampleInstrumentedTest.java @@ -0,0 +1,24 @@ +package com.example.rally_scrollable_tab; + +import android.content.Context; +import androidx.test.InstrumentationRegistry; +import androidx.test.runner.AndroidJUnit4; + +import org.junit.Test; +import org.junit.runner.RunWith; + +import static org.junit.Assert.*; + +/** + * Instrumented test, which will execute on an Android device. + * + * @see Testing documentation + */ +@RunWith(AndroidJUnit4.class) public class ExampleInstrumentedTest { + @Test public void useAppContext() { + // Context of the app under test. + Context appContext = InstrumentationRegistry.getTargetContext(); + + assertEquals("com.example.rally_scrollable_tab.test", appContext.getPackageName()); + } +} diff --git a/rally_scrollable_tab/src/main/AndroidManifest.xml b/rally_scrollable_tab/src/main/AndroidManifest.xml new file mode 100644 index 0000000..6dce5b3 --- /dev/null +++ b/rally_scrollable_tab/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + diff --git a/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/RallyScrollableTab.kt b/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/RallyScrollableTab.kt new file mode 100644 index 0000000..4d4361f --- /dev/null +++ b/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/RallyScrollableTab.kt @@ -0,0 +1,124 @@ +package com.example.rally_scrollable_tab + +import android.animation.ArgbEvaluator +import android.content.Context +import android.graphics.Color +import android.util.AttributeSet +import android.view.View +import android.widget.TextView +import androidx.annotation.StyleRes +import androidx.recyclerview.widget.LinearLayoutManager +import androidx.recyclerview.widget.LinearSnapHelper +import androidx.recyclerview.widget.RecyclerView + +/** + * Created by Chan Myae Aung on 8/4/19. + */ +//click listener +//integration with viewpager +class RallyScrollableTab : RecyclerView { + + private val tabAdapter by lazy { TabAdapter(style = tabTextStyle) } + private var selectedColor = Color.WHITE + private var unSelectedColor = Color.GRAY + private var tabTextStyle = TabStyle(R.style.TabTextStyle) + + constructor( + context: Context, + attrs: AttributeSet? + ) : super(context, attrs) { + init(attrs) + } + + constructor( + context: Context, + attrs: AttributeSet?, + defStyle: Int + ) : super(context, attrs, defStyle) { + init(attrs) + } + + private fun init(set: AttributeSet?) { + initAttributes(set) + + layoutManager = LinearLayoutManager(context, HORIZONTAL, false) + setHasFixedSize(true) + adapter = tabAdapter + + val snapHelper = LinearSnapHelper() + snapHelper.attachToRecyclerView(this) + + createPagerStyle() + + addOnScrollListener(object : OnScrollListener() { + override fun onScrolled( + recyclerView: RecyclerView, + dx: Int, + dy: Int + ) { + super.onScrolled(recyclerView, dx, dy) + post { + (0 until childCount).forEach { + val child = getChildAt(it) + val childCenterX = (child.left + child.right) / 2 + val scaleValue = getGaussianScale(childCenterX, 1f, 1f, 150.toDouble()) +// child.scaleX = scaleValue +// child.scaleY = scaleValue + colorView(child, scaleValue) + } + } + } + }) + } + + private fun initAttributes(set: AttributeSet?) { + val ta = context.obtainStyledAttributes(set, R.styleable.RallyScrollableTab) + selectedColor = ta.getColor(R.styleable.RallyScrollableTab_selectedColor, Color.WHITE) + unSelectedColor = ta.getColor(R.styleable.RallyScrollableTab_unSelectedColor, Color.GRAY) + tabTextStyle = + TabStyle(ta.getResourceId(R.styleable.RallyScrollableTab_tabTextStyle, R.style.TabTextStyle)) + ta.recycle() + + } + + private fun createPagerStyle() { + //add padding and set clipToPadding false so other tab items are also visible at left,right edge screen + clipToPadding = false + val halfSWidth = context.resources.displayMetrics.widthPixels / 2 + val padding = halfSWidth / 2 + setPadding(padding, 0, padding, 0) + } + + fun addTabs(list: List) { + tabAdapter.addAll(list) + } + + private fun colorView( + child: View, + scaleValue: Float + ) { + val percent = (scaleValue - 1) / 1f + val color = ArgbEvaluator().evaluate(percent, unSelectedColor, selectedColor) as Int + child.findViewById(R.id.tvTab) + .setTextColor(color) + + } + + private fun getGaussianScale( + childCenterX: Int, + minScaleOffest: Float, + scaleFactor: Float, + spreadFactor: Double + ): Float { + val recyclerCenterX = (left + right) / 2 + return (Math.pow( + Math.E, + -Math.pow(childCenterX - recyclerCenterX.toDouble(), 2.toDouble()) / (2 * Math.pow( + spreadFactor, + 2.toDouble() + )) + ) * scaleFactor + minScaleOffest).toFloat() + } +} + +data class TabStyle(@StyleRes val tabTextStyle: Int) diff --git a/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/TabAdapter.kt b/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/TabAdapter.kt new file mode 100644 index 0000000..6726feb --- /dev/null +++ b/rally_scrollable_tab/src/main/java/com/example/rally_scrollable_tab/TabAdapter.kt @@ -0,0 +1,53 @@ +package com.example.rally_scrollable_tab + +import android.view.LayoutInflater +import android.view.View +import android.view.ViewGroup +import android.widget.TextView +import androidx.annotation.StyleRes +import androidx.core.widget.TextViewCompat +import androidx.recyclerview.widget.RecyclerView + +/** + * Created by Chan Myae Aung on 8/4/19. + */ +class TabAdapter( + private val tabs: MutableList = mutableListOf(), + private val style: TabStyle +) : RecyclerView.Adapter() { + + override fun onCreateViewHolder( + parent: ViewGroup, + viewType: Int + ): TabViewHolder { + val view = LayoutInflater.from(parent.context) + .inflate(R.layout.item_tab, parent, false) + + TextViewCompat.setTextAppearance(view.findViewById(R.id.tvTab), style.tabTextStyle) + return TabViewHolder(view) + } + + override fun getItemCount(): Int { + return tabs.size + } + + override fun onBindViewHolder( + holder: TabViewHolder, + position: Int + ) { + holder.bind(tabs[position]) + } + + fun addAll(list: List) { + tabs.clear() + tabs.addAll(list) + notifyDataSetChanged() + } +} + +class TabViewHolder(view: View) : RecyclerView.ViewHolder(view) { + private val tab: TextView = view.findViewById(R.id.tvTab) + fun bind(model: String) { + tab.text = model + } +} diff --git a/rally_scrollable_tab/src/main/res/layout/item_tab.xml b/rally_scrollable_tab/src/main/res/layout/item_tab.xml new file mode 100644 index 0000000..efbf51b --- /dev/null +++ b/rally_scrollable_tab/src/main/res/layout/item_tab.xml @@ -0,0 +1,22 @@ + + + + + + \ No newline at end of file diff --git a/rally_scrollable_tab/src/main/res/values/attrs.xml b/rally_scrollable_tab/src/main/res/values/attrs.xml new file mode 100644 index 0000000..6a2c229 --- /dev/null +++ b/rally_scrollable_tab/src/main/res/values/attrs.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/rally_scrollable_tab/src/main/res/values/strings.xml b/rally_scrollable_tab/src/main/res/values/strings.xml new file mode 100644 index 0000000..8dfff9e --- /dev/null +++ b/rally_scrollable_tab/src/main/res/values/strings.xml @@ -0,0 +1,3 @@ + + rally_scrollable_tab + diff --git a/rally_scrollable_tab/src/main/res/values/styles.xml b/rally_scrollable_tab/src/main/res/values/styles.xml new file mode 100644 index 0000000..9ce5991 --- /dev/null +++ b/rally_scrollable_tab/src/main/res/values/styles.xml @@ -0,0 +1,6 @@ + + + + \ No newline at end of file diff --git a/rally_scrollable_tab/src/test/java/com/example/rally_scrollable_tab/ExampleUnitTest.java b/rally_scrollable_tab/src/test/java/com/example/rally_scrollable_tab/ExampleUnitTest.java new file mode 100644 index 0000000..970fd18 --- /dev/null +++ b/rally_scrollable_tab/src/test/java/com/example/rally_scrollable_tab/ExampleUnitTest.java @@ -0,0 +1,16 @@ +package com.example.rally_scrollable_tab; + +import org.junit.Test; + +import static org.junit.Assert.*; + +/** + * Example local unit test, which will execute on the development machine (host). + * + * @see Testing documentation + */ +public class ExampleUnitTest { + @Test public void addition_isCorrect() { + assertEquals(4, 2 + 2); + } +} \ No newline at end of file diff --git a/settings.gradle b/settings.gradle index e37def5..11f5b61 100644 --- a/settings.gradle +++ b/settings.gradle @@ -1 +1 @@ -include ':app', ':themebuilder', ':design_system', ':rally_pie', ':rally_line_chart', ':rally_line_indicator' +include ':app', ':themebuilder', ':design_system', ':rally_pie', ':rally_line_chart', ':rally_line_indicator', ':rally_scrollable_tab'