diff --git a/app/build.gradle.kts b/app/build.gradle.kts
index 9f251a0..3f95c21 100644
--- a/app/build.gradle.kts
+++ b/app/build.gradle.kts
@@ -14,7 +14,7 @@ android {
defaultConfig {
applicationId = "com.example.androidtechsample"
- minSdk = 23
+ minSdk = 26
targetSdk = 31
versionCode = 1
versionName = "1.0"
@@ -43,6 +43,7 @@ dependencies {
implementation(project(":feature:twitter:twitter-core"))
implementation(project(":feature:twitter:home"))
implementation(project(":feature:material"))
+ implementation(project(":feature:chart"))
implementation(Dep.AndroidX.appCompat)
implementation(Dep.AndroidX.core)
diff --git a/app/src/main/java/com/example/androidtechsample/ui/PlaygroundFragment.kt b/app/src/main/java/com/example/androidtechsample/ui/PlaygroundFragment.kt
index f13ca70..1c5a578 100644
--- a/app/src/main/java/com/example/androidtechsample/ui/PlaygroundFragment.kt
+++ b/app/src/main/java/com/example/androidtechsample/ui/PlaygroundFragment.kt
@@ -44,33 +44,16 @@ class PlaygroundFragment : Fragment() {
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
with(binding) {
- buttonPlaygroundToDesignMock.setOnClickListener {
- navigator(R.id.to_fragment_biometric)
- }
- toMotionLayout.setOnClickListener {
- navigator(R.id.to_fragment_motion)
- }
- toGroupieView.setOnClickListener {
- navigator(R.id.to_fragment_groupie)
- }
- toSpanView.setOnClickListener {
- navigator(R.id.to_fragment_span)
- }
- toNotificationView.setOnClickListener {
- navigator(R.id.to_fragment_notification)
- }
- toListView.setOnClickListener {
- navigator(R.id.to_fragment_list)
- }
- toCameraView.setOnClickListener {
- cameraPermissionRequestLauncher.launch(REQUIRED_PERMISSIONS)
- }
- toComposeView.setOnClickListener {
- navigator(R.id.to_fragment_compose)
- }
- toMaterialView.setOnClickListener {
- navigator(R.id.to_fragment_material)
- }
+ buttonPlaygroundToDesignMock.setOnClickListener { navigator(R.id.to_fragment_biometric) }
+ toMotionLayout.setOnClickListener { navigator(R.id.to_fragment_motion) }
+ toGroupieView.setOnClickListener { navigator(R.id.to_fragment_groupie) }
+ toSpanView.setOnClickListener { navigator(R.id.to_fragment_span) }
+ toNotificationView.setOnClickListener { navigator(R.id.to_fragment_notification) }
+ toListView.setOnClickListener { navigator(R.id.to_fragment_list) }
+ toCameraView.setOnClickListener { cameraPermissionRequestLauncher.launch(REQUIRED_PERMISSIONS) }
+ toComposeView.setOnClickListener { navigator(R.id.to_fragment_compose) }
+ toMaterialView.setOnClickListener { navigator(R.id.to_fragment_material) }
+ toChartView.setOnClickListener { navigator(R.id.to_fragment_chart) }
}
}
}
diff --git a/app/src/main/res/layout/fragment_playground.xml b/app/src/main/res/layout/fragment_playground.xml
index 551bc62..7737326 100644
--- a/app/src/main/res/layout/fragment_playground.xml
+++ b/app/src/main/res/layout/fragment_playground.xml
@@ -110,6 +110,14 @@
android:layout_marginVertical="4dp"
android:text="@string/playground_camera_view" />
+
+
diff --git a/feature/chart/src/main/java/com/example/chart/ChartFragment.kt b/feature/chart/src/main/java/com/example/chart/ChartFragment.kt
new file mode 100644
index 0000000..f31142c
--- /dev/null
+++ b/feature/chart/src/main/java/com/example/chart/ChartFragment.kt
@@ -0,0 +1,255 @@
+package com.example.chart
+
+import android.graphics.Color
+import android.graphics.Typeface
+import android.icu.text.SimpleDateFormat
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.core.content.ContextCompat
+import androidx.fragment.app.Fragment
+import com.example.chart.databinding.FragmentChartBinding
+import com.github.mikephil.charting.components.XAxis.XAxisPosition
+import com.github.mikephil.charting.data.BarData
+import com.github.mikephil.charting.data.BarDataSet
+import com.github.mikephil.charting.data.BarEntry
+import com.github.mikephil.charting.data.CombinedData
+import com.github.mikephil.charting.data.Entry
+import com.github.mikephil.charting.data.LineData
+import com.github.mikephil.charting.data.LineDataSet
+import com.github.mikephil.charting.formatter.ValueFormatter
+import com.github.mikephil.charting.interfaces.datasets.ILineDataSet
+import java.time.LocalDate
+import java.util.*
+
+class ChartFragment : Fragment() {
+
+ private lateinit var binding: FragmentChartBinding
+
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View {
+ binding = FragmentChartBinding.inflate(inflater)
+ return binding.root
+ }
+
+ override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
+ super.onViewCreated(view, savedInstanceState)
+
+ createLineChart()
+ createCombinedChart()
+ }
+
+ private fun createLineChart() {
+ //表示用サンプルデータの作成//
+ val follow = listOf(
+ Pair(createMonth(4), 1000),
+ Pair(createMonth(5), 970),
+ Pair(createMonth(6), 980),
+ Pair(createMonth(7), 1020),
+ Pair(createMonth(8), 1130),
+ Pair(createMonth(9), 1250),
+ Pair(createMonth(10), 1300),
+ Pair(createMonth(11), 1400),
+ )
+
+ // Entryにデータ格納
+ val entryList = mutableListOf()//1本目の線
+ follow.map {
+ entryList.add(
+ Entry(it.first.toFloat(), it.second.toFloat())
+ )
+ }
+
+ // DataSetにデータ格納
+ val lineDataSet = LineDataSet(entryList, "square")
+ // DataSetにフォーマット指定(3章で詳説)
+ // 線の色
+ lineDataSet.color = ContextCompat.getColor(requireContext(), R.color.spindle_accent_primary)
+ // 線の太さ
+ lineDataSet.lineWidth = 3f
+ // 背景色を出すかの true false
+ lineDataSet.setDrawFilled(true)
+ // 背景色指定
+ lineDataSet.fillDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.grad_line_chart)
+ // 座標の大きさ
+ lineDataSet.circleRadius = 5f
+ // 座標の色
+ lineDataSet.circleColors = listOf(ContextCompat.getColor(requireContext(), R.color.white))
+ // 座標中心の表示
+ lineDataSet.setDrawCircleHole(true)
+ // 座標中心の大きさ(circleRadiusより小さい値)
+ lineDataSet.circleHoleRadius = 4f
+ // 座標中心の色
+ lineDataSet.circleHoleColor =
+ ContextCompat.getColor(requireContext(), R.color.spindle_accent_primary)
+ // データの値を記す。0fで記載なし。
+ lineDataSet.valueTextSize = 0f
+ lineDataSet.label = ""
+ // 表示モード
+ lineDataSet.mode = LineDataSet.Mode.CUBIC_BEZIER
+
+ //リストに格納
+ val lineDataSets = mutableListOf()
+ lineDataSets.add(lineDataSet)
+
+ // LineDataにLineDataSet格納
+ val lineData = LineData(lineDataSets)
+ // LineChartにLineData格納
+ binding.lineChart.data = lineData
+ // Chartのフォーマット指定
+ binding.lineChart.apply {
+ // x軸設定
+ xAxis.apply {
+ isEnabled = true
+ textColor = Color.BLACK
+ textSize = 12f
+ typeface = Typeface.DEFAULT_BOLD
+ position = XAxisPosition.BOTTOM
+ valueFormatter = MonthValueFormatter()
+ labelCount = 4
+
+ }
+ // y軸の設定
+ axisRight.isEnabled = false
+ axisLeft.apply {
+ textSize = 12f
+ typeface = Typeface.DEFAULT_BOLD
+ valueFormatter = FollowValueFormatter()
+ }
+ // description
+ description.isEnabled = false
+ }
+ // アニメーション
+ binding.lineChart.animateXY(1000, 1000)
+
+ // lineChart更新
+ binding.lineChart.invalidate()
+ }
+
+ private fun createMonth(month: Int): Int = LocalDate.of(2020, month, 1).monthValue
+
+ private fun createCombinedChart() {
+
+ //表示用サンプルデータの作成//
+ val weekData = listOf(
+ 150,
+ 90,
+ 200,
+ 150,
+ 100,
+ 250,
+ 150
+ )
+
+ val averageData = List(9) { 150 }
+
+ //①Entryにデータ格納
+ val entryList = mutableListOf()
+ weekData.mapIndexed { index, it ->
+ entryList.add(BarEntry((index + 1).toFloat(), it.toFloat()))
+ }
+ val averageList = mutableListOf()
+ averageData.mapIndexed { index, it ->
+ averageList.add(Entry(index.toFloat(), it.toFloat()))
+ }
+
+ // ②DataSetにデータ格納
+ val barDataSet = BarDataSet(entryList, "square")
+ val lineDataSet = LineDataSet(averageList, "square")
+
+ /**
+ * 棒グラフの設定
+ */
+ // 線の色
+ barDataSet.color = ContextCompat.getColor(requireContext(), R.color.spindle_accent_primary)
+ barDataSet.label = ""
+ // 値の表示有無
+ barDataSet.setDrawValues(false)
+
+ /**
+ * 線グラフの設定
+ */
+ lineDataSet.color = ContextCompat.getColor(requireContext(), R.color.spindle_accent_secondary)
+ lineDataSet.lineWidth = 2f
+ lineDataSet.setDrawCircles(false)
+ lineDataSet.label = ""
+ lineDataSet.setDrawValues(false)
+ // 点線の指定
+ lineDataSet.enableDashedLine(20f, 30f, 0f)
+
+
+ //④BarDataにBarDataSet格納
+ val barData = BarData(barDataSet)
+ val averageLineData = LineData(lineDataSet)
+
+ val combinedData = CombinedData()
+ combinedData.setData(barData)
+ combinedData.setData(averageLineData)
+
+ // 棒の幅の調整
+ barData.barWidth = 0.5f
+
+ //⑤BarChartのフォーマット指定
+ binding.combinedChart.apply {
+ // Zoomの制御
+ setScaleEnabled(false)
+ // 棒グラフの左下のマーカーの制御
+ legend.isEnabled = false
+ // 右下のdescription labelの制御
+ description.isEnabled = false
+
+ // x軸設定
+ xAxis.apply {
+ isEnabled = true
+ textColor = Color.BLACK
+ position = XAxisPosition.BOTTOM
+ valueFormatter = object : ValueFormatter() {
+
+ override fun getFormattedValue(value: Float): String {
+ // value == 0の時折線グラフのindex0に当たるのでreturnする
+ if (value.toInt() == 0) return ""
+ if (weekData.size >= value) {
+ val simpleDateFormat = SimpleDateFormat("M/d", Locale.getDefault())
+ val entriesTimestampMills: MutableList = mutableListOf(
+ 1614524400000, // 2021/03/01 00:00:00
+ 1614610800000, // 2021/03/02 00:00:00
+ 1614697200000, // 2021/03/03 00:00:00
+ 1614783600000, // 2021/03/04 00:00:00
+ 1614870000000, // 2021/03/05 00:00:00
+ 1614956400000, // 2021/03/06 00:00:00
+ 1615042800000 // 2021/03/07 00:00:00
+ )
+ // value には 0, 1, 2... という index が入ってくるので
+ // index からタイムスタンプを取得する
+ val timestampMills = entriesTimestampMills[value.toInt() - 1]
+ val date = Date(timestampMills)
+ return simpleDateFormat.format(date)
+ } else {
+ return ""
+ }
+ }
+ }
+ axisMinimum = 0f
+
+ }
+ // y軸設定
+ axisRight.isEnabled = false
+ axisLeft.apply {
+ textColor = ContextCompat.getColor(requireContext(), R.color.black)
+ }
+
+ data = combinedData
+ // 選択ハイライトの制御
+ data.isHighlightEnabled = false
+ }
+
+ // アニメーション
+ binding.combinedChart.animateXY(1000, 1000)
+
+ binding.combinedChart.invalidate()
+ }
+}
diff --git a/feature/chart/src/main/java/com/example/chart/FollowValueFormatter.kt b/feature/chart/src/main/java/com/example/chart/FollowValueFormatter.kt
new file mode 100644
index 0000000..5fe1e65
--- /dev/null
+++ b/feature/chart/src/main/java/com/example/chart/FollowValueFormatter.kt
@@ -0,0 +1,9 @@
+package com.example.chart
+
+import com.github.mikephil.charting.formatter.ValueFormatter
+
+class FollowValueFormatter : ValueFormatter() {
+ override fun getFormattedValue(value: Float): String {
+ return (value.toInt() / 1000.0).toString() + "千"
+ }
+}
diff --git a/feature/chart/src/main/java/com/example/chart/MonthValueFormatter.kt b/feature/chart/src/main/java/com/example/chart/MonthValueFormatter.kt
new file mode 100644
index 0000000..7b607a1
--- /dev/null
+++ b/feature/chart/src/main/java/com/example/chart/MonthValueFormatter.kt
@@ -0,0 +1,9 @@
+package com.example.chart
+
+import com.github.mikephil.charting.formatter.ValueFormatter
+
+class MonthValueFormatter : ValueFormatter() {
+ override fun getFormattedValue(value: Float): String {
+ return value.toInt().toString() + "月"
+ }
+}
diff --git a/feature/chart/src/main/res/drawable/grad_line_chart.xml b/feature/chart/src/main/res/drawable/grad_line_chart.xml
new file mode 100644
index 0000000..9c3706a
--- /dev/null
+++ b/feature/chart/src/main/res/drawable/grad_line_chart.xml
@@ -0,0 +1,7 @@
+
+
+
+
diff --git a/feature/chart/src/main/res/layout/fragment_chart.xml b/feature/chart/src/main/res/layout/fragment_chart.xml
new file mode 100644
index 0000000..4b3982f
--- /dev/null
+++ b/feature/chart/src/main/res/layout/fragment_chart.xml
@@ -0,0 +1,64 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/feature/core/src/main/res/navigation/nav_main.xml b/feature/core/src/main/res/navigation/nav_main.xml
index 0c95b1e..fa30caa 100644
--- a/feature/core/src/main/res/navigation/nav_main.xml
+++ b/feature/core/src/main/res/navigation/nav_main.xml
@@ -34,6 +34,9 @@
+
+
+
+
diff --git a/feature/resources/src/main/res/values/colors.xml b/feature/resources/src/main/res/values/colors.xml
index 46c7b49..aebc788 100644
--- a/feature/resources/src/main/res/values/colors.xml
+++ b/feature/resources/src/main/res/values/colors.xml
@@ -45,4 +45,8 @@
- @color/deep_orange_200
+
+ #298737
+ #82BE28
+
diff --git a/feature/resources/src/main/res/values/strings.xml b/feature/resources/src/main/res/values/strings.xml
index 6591d60..2bb9e6d 100644
--- a/feature/resources/src/main/res/values/strings.xml
+++ b/feature/resources/src/main/res/values/strings.xml
@@ -14,6 +14,7 @@
SpanView
NotificationView
CameraView
+ ChartView
HelloCompose
カメラの許可をしてください
ListView
@@ -98,4 +99,9 @@
Notification
DM
+
+ Chart
+ LineChart
+ BarChart
+ CombinedChart
diff --git a/settings.gradle.kts b/settings.gradle.kts
index 1114b19..7628088 100644
--- a/settings.gradle.kts
+++ b/settings.gradle.kts
@@ -9,3 +9,4 @@ include(":feature:ameba:followfeed")
include(":feature:twitter:home")
include(":feature:twitter:twitter-core")
include(":feature:material")
+include(":feature:chart")