Skip to content

Commit

Permalink
add rally scrollable tab
Browse files Browse the repository at this point in the history
  • Loading branch information
CMyae committed Aug 4, 2019
1 parent fcb55fb commit 7a28d4d
Show file tree
Hide file tree
Showing 18 changed files with 347 additions and 3 deletions.
1 change: 1 addition & 0 deletions .idea/gradle.xml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions app/build.gradle
Expand Up @@ -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"
Expand Down
12 changes: 12 additions & 0 deletions app/src/main/java/io/material/rally/ui/detail/DetailActivity.kt
Expand Up @@ -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"
)
)
}
}
15 changes: 13 additions & 2 deletions app/src/main/res/layout/activity_detail.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
Expand All @@ -15,4 +15,15 @@
android:transitionName="DetailView"
android:background="@color/color_secondary"/>

</LinearLayout>
<com.example.rally_scrollable_tab.RallyScrollableTab
android:id="@+id/tab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:background="@color/color_secondary_variant"
app:selectedColor="@android:color/white"
app:unSelectedColor="#B3DDDDDD"
app:tabTextStyle="@style/TextAppearance.RallyScrollableTab"
/>

</FrameLayout>
4 changes: 4 additions & 0 deletions design_system/src/main/res/values/type.xml
Expand Up @@ -106,4 +106,8 @@
<item name="android:textSize">10sp</item>
</style>

<style name="TextAppearance.RallyScrollableTab" parent="TextAppearance.Design.Tab">
<item name="android:letterSpacing">0.2</item>
</style>

</resources>
1 change: 1 addition & 0 deletions rally_scrollable_tab/.gitignore
@@ -0,0 +1 @@
/build
35 changes: 35 additions & 0 deletions 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'
}
21 changes: 21 additions & 0 deletions 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
@@ -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 <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@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());
}
}
2 changes: 2 additions & 0 deletions rally_scrollable_tab/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.rally_scrollable_tab"/>
@@ -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<String>) {
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<TextView>(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)
@@ -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<String> = mutableListOf(),
private val style: TabStyle
) : RecyclerView.Adapter<TabViewHolder>() {

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<String>) {
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
}
}
22 changes: 22 additions & 0 deletions rally_scrollable_tab/src/main/res/layout/item_tab.xml
@@ -0,0 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
xmlns:tools="http://schemas.android.com/tools"
android:background="?attr/selectableItemBackground"
android:clickable="true"
>

<TextView
android:id="@+id/tvTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="Tab 1"
android:textColor="#fff"
android:textStyle="bold"
android:gravity="center"
android:paddingTop="16dp"
android:paddingBottom="16dp"
/>

</FrameLayout>
8 changes: 8 additions & 0 deletions rally_scrollable_tab/src/main/res/values/attrs.xml
@@ -0,0 +1,8 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="RallyScrollableTab">
<attr name="selectedColor" format="color"/>
<attr name="unSelectedColor" format="color"/>
<attr name="tabTextStyle" format="reference"/>
</declare-styleable>
</resources>
3 changes: 3 additions & 0 deletions rally_scrollable_tab/src/main/res/values/strings.xml
@@ -0,0 +1,3 @@
<resources>
<string name="app_name">rally_scrollable_tab</string>
</resources>
6 changes: 6 additions & 0 deletions rally_scrollable_tab/src/main/res/values/styles.xml
@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="TabTextStyle">
<item name="android:textSize">16sp</item>
</style>
</resources>

0 comments on commit 7a28d4d

Please sign in to comment.