Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ android {

defaultConfig {
applicationId = "com.example.androidtechsample"
minSdk = 23
minSdk = 26
targetSdk = 31
versionCode = 1
versionName = "1.0"
Expand Down Expand Up @@ -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)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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) }
}
}
}
8 changes: 8 additions & 0 deletions app/src/main/res/layout/fragment_playground.xml
Original file line number Diff line number Diff line change
Expand Up @@ -110,6 +110,14 @@
android:layout_marginVertical="4dp"
android:text="@string/playground_camera_view" />

<com.google.android.material.button.MaterialButton
android:id="@+id/to_chart_view"
style="@style/ButtonRectangleFill"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginVertical="4dp"
android:text="@string/playground_chart_view" />

<TextView
style="@style/Text.PrimaryColor.Head3"
android:layout_width="wrap_content"
Expand Down
1 change: 1 addition & 0 deletions buildSrc/src/main/java/Dep.kt
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ object Dep {
}

const val coil = "io.coil-kt:coil-compose:1.4.0"
const val chart = "com.github.PhilJay:MPAndroidChart:v3.1.0"

object Test {
const val junit4 = "junit:junit:4.13.2"
Expand Down
1 change: 1 addition & 0 deletions feature/chart/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
24 changes: 24 additions & 0 deletions feature/chart/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import com.example.buildsrc.Dep

plugins {
id("com.android.library")
id("org.jetbrains.kotlin.android")
}

android {
compileSdk = 31
defaultConfig {
minSdk = 26
}
buildFeatures {
dataBinding = true
}
}

dependencies {
implementation(project(":feature:resources"))
implementation(project(":feature:core"))

implementation(Dep.AndroidX.constraintLayout)
implementation(Dep.chart)
}
Empty file.
21 changes: 21 additions & 0 deletions feature/chart/proguard-rules.pro
Original file line number Diff line number Diff line change
@@ -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
1 change: 1 addition & 0 deletions feature/chart/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<manifest package="com.example.chart" />
255 changes: 255 additions & 0 deletions feature/chart/src/main/java/com/example/chart/ChartFragment.kt
Original file line number Diff line number Diff line change
@@ -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<Entry>()//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<ILineDataSet>()
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<BarEntry>()
weekData.mapIndexed { index, it ->
entryList.add(BarEntry((index + 1).toFloat(), it.toFloat()))
}
val averageList = mutableListOf<Entry>()
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<Long> = 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()
}
}
Loading