▶Do it! 안드로이드 앱 프로그래밍(정재곤 지음) 을 참고하여 제작하였습니다.
※ 개발 방법을 일일히 기록한 강의 형식의 글이 아닙니다. 개발하면서 대략적으로 중요하고, 새로 얻게된 지식 부분만 기록한 글입니다. 자세한 내용은 깃허브 파일 참조.
이전글
2020.11.27 - [안드로이드 스튜디오/개발] - [Android 개발일지] 안드로이드 스튜디오로 일기장 만들기 - 1 (기획, 메인, 목록 화면 만들기)
작성 화면 만들기
fragment_2.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".Fragment2">
<RelativeLayout
android:id="@+id/topLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:padding="4dp">
<ImageView
android:id="@+id/weatherIcon"
android:layout_width="28dp"
android:layout_height="28dp"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:src="@drawable/weather_1" />
<TextView
android:id="@+id/dateTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:textSize="26sp"
android:text="OO월 OO일"/>
<TextView
android:id="@+id/locationTextView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:textSize="13sp"
android:text="전주시 덕진구"/>
</RelativeLayout>
<RelativeLayout
android:id="@+id/contentsLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="@+id/topLayout"
android:layout_above="@+id/moodLayout" >
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="8dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_alignParentTop="true"
app:cardBackgroundColor="#FFFFFFFF"
app:cardCornerRadius="10dp"
app:cardElevation="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<EditText
android:id="@+id/contentsInput"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:maxLines="1"
android:textSize="32sp"
android:hint="내용 입력"
/>
<ImageView
android:id="@+id/pictureImageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="8dp"
android:src="@drawable/imagetoset" />
</LinearLayout>
</androidx.cardview.widget.CardView>
</RelativeLayout>
<androidx.cardview.widget.CardView
android:id="@+id/moodLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:layout_marginLeft="4dp"
android:layout_marginRight="4dp"
android:layout_marginBottom="4dp"
android:layout_above="@+id/bottomLayout"
app:cardBackgroundColor="#FFFFFFFF"
app:cardCornerRadius="10dp"
app:cardElevation="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<com.github.channguyen.rsv.RangeSliderView
android:id="@+id/sliderView"
android:layout_width="match_parent"
android:layout_height="40dp"
android:layout_marginTop="20dp"
app:filledColor="#FF6600"
app:emptyColor="#a8aeb8"
app:rangeCount="5"
app:sliderRadiusPercent="0.4"
app:barHeightPercent="0.1" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="10dp"
android:orientation="horizontal">
<ImageView
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:src="@drawable/smile1_48"/>
<ImageView
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:src="@drawable/smile2_48"/>
<ImageView
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:src="@drawable/smile3_48"/>
<ImageView
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:src="@drawable/smile4_48"/>
<ImageView
android:layout_width="0dp"
android:layout_height="30dp"
android:layout_weight="1"
android:src="@drawable/smile5_48"/>
</LinearLayout>
</LinearLayout>
</androidx.cardview.widget.CardView>
<RelativeLayout
android:id="@+id/bottomLayout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_marginBottom="60dp"
android:paddingTop="10dp"
android:paddingBottom="10dp">
<Button
android:id="@+id/saveButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_marginLeft="20dp"
android:background="@drawable/select_button"
android:text="저장"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/deleteButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:background="@drawable/select_button"
android:text="삭제"
android:textColor="@android:color/white"/>
<Button
android:id="@+id/closeButton"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_marginRight="20dp"
android:background="@drawable/select_button"
android:text="닫기"
android:textColor="@android:color/white"/>
</RelativeLayout>
</RelativeLayout>
프래그먼트로 구성
Fragment2
package org.techtown.diary
import android.content.Context
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.fragment.app.Fragment
import kotlinx.android.synthetic.main.fragment_2.view.*
class Fragment2 : Fragment() {
private var _context : Context? = null
private var listener : OnTabItemSelectedListener? = null
override fun onAttach(context: Context) {
super.onAttach(context)
this._context = context
if(context is OnTabItemSelectedListener){
listener = context
}
}
override fun onDetach() {
super.onDetach()
if(context!=null){
_context = null
listener = null
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var rootView = inflater.inflate(R.layout.fragment_2, container, false) as ViewGroup
initUI(rootView)
return rootView
}
private fun initUI(rootView : ViewGroup){
rootView.saveButton.setOnClickListener{
listener?.onTabSelected(0)
} // 저장 버튼 클릭시 목록으로
rootView.deleteButton.setOnClickListener {
listener?.onTabSelected(0)
} // 삭제 버튼 클릭시 목록으로
rootView.closeButton.setOnClickListener {
listener?.onTabSelected(0)
} // 닫기 버튼 클릭시 목록으로
rootView.sliderView.setOnSlideListener {
index -> Toast.makeText(context, "moodIndex changed to $index", Toast.LENGTH_SHORT).show()
} // 기분 선택되면 호출될 함수
rootView.sliderView.setInitialIndex(2) // 기본값을 중간으로
}
}
통계 화면 만들기
fragment_3.xml
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:layout_marginBottom="60dp"
android:orientation="vertical"
tools:context=".Fragment3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
app:cardBackgroundColor="#FFFFFFFF"
app:cardCornerRadius="10dp"
app:cardElevation="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textStyle="bold"
android:text="기분별 비율"
/>
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/chart1"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
app:cardBackgroundColor="#FFFFFFFF"
app:cardCornerRadius="10dp"
app:cardElevation="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textStyle="bold"
android:text="요일별 기분"
/>
<com.github.mikephil.charting.charts.BarChart
android:id="@+id/chart2"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_marginTop="10dp"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
<androidx.cardview.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginLeft="10dp"
android:layout_marginRight="10dp"
android:layout_marginBottom="5dp"
app:cardBackgroundColor="#FFFFFFFF"
app:cardCornerRadius="10dp"
app:cardElevation="5dp" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="10dp"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textSize="24sp"
android:textStyle="bold"
android:text="기분 변화"
/>
<com.github.mikephil.charting.charts.LineChart
android:id="@+id/chart3"
android:layout_width="250dp"
android:layout_height="250dp"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:layout_gravity="center_horizontal"/>
</LinearLayout>
</androidx.cardview.widget.CardView>
</LinearLayout>
</ScrollView>
MPAndroidChart 라이브러리 활용
Fragment3
package org.techtown.diary
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.fragment.app.Fragment
import com.github.mikephil.charting.charts.BarChart
import com.github.mikephil.charting.charts.LineChart
import com.github.mikephil.charting.charts.PieChart
import com.github.mikephil.charting.components.XAxis
import com.github.mikephil.charting.components.YAxis
import com.github.mikephil.charting.data.*
import com.github.mikephil.charting.utils.ColorTemplate
import com.github.mikephil.charting.utils.MPPointF
import kotlinx.android.synthetic.main.fragment_3.view.*
import java.text.SimpleDateFormat
import java.util.*
import java.util.concurrent.TimeUnit
class Fragment3 : Fragment() {
var chart : PieChart? = null
var chart2 : BarChart? = null
var chart3 : LineChart? = null
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
var rootView = inflater.inflate(R.layout.fragment_3, container, false) as ViewGroup
initUI(rootView)
return rootView
}
private fun initUI(rootView : ViewGroup){
chart = rootView.chart1
chart!!.setUsePercentValues(true)
chart!!.description.isEnabled = false
chart!!.centerText = "기분별 비율"
chart!!.setTransparentCircleColor(Color.WHITE)
chart!!.setTransparentCircleAlpha(110)
chart!!.holeRadius = 58f
chart!!.transparentCircleRadius = 61f
chart!!.setDrawCenterText(true)
chart!!.isHighlightPerTapEnabled = true
val legent1 = chart!!.legend
legent1.isEnabled = false
chart!!.setEntryLabelColor(Color.WHITE)
chart!!.setEntryLabelTextSize(12f)
setData1()
chart2 = rootView.chart2
chart2!!.setDrawValueAboveBar(true)
chart2!!.getDescription().isEnabled = false
chart2!!.setDrawGridBackground(false)
val xAxis = chart2!!.getXAxis()
xAxis.isEnabled = false
val leftAxis = chart2!!.getAxisLeft()
leftAxis.setLabelCount(6, false)
leftAxis.axisMinimum = 0.0f
leftAxis.isGranularityEnabled = true
leftAxis.granularity = 1f
val rightAxis = chart2!!.getAxisRight()
rightAxis.isEnabled = false
val legend2 = chart2!!.getLegend()
legend2.isEnabled = false
chart2!!.animateXY(1500, 1500)
setData2()
chart3 = rootView.chart3
chart3!!.getDescription().isEnabled = false
chart3!!.setDrawGridBackground(false)
// set an alternative background color
// set an alternative background color
chart3!!.setBackgroundColor(Color.WHITE)
chart3!!.setViewPortOffsets(0f, 0f, 0f, 0f)
// get the legend (only possible after setting data)
// get the legend (only possible after setting data)
val legend3 = chart3!!.getLegend()
legend3.isEnabled = false
val xAxis3 = chart3!!.getXAxis()
xAxis3.position = XAxis.XAxisPosition.BOTTOM_INSIDE
xAxis3.textSize = 10f
xAxis3.textColor = Color.WHITE
xAxis3.setDrawAxisLine(false)
xAxis3.setDrawGridLines(true)
xAxis3.textColor = Color.rgb(255, 192, 56)
xAxis3.setCenterAxisLabels(true)
xAxis3.granularity = 1f
xAxis3.setValueFormatter(object : ValueFormatter() {
private val mFormat =
SimpleDateFormat("MM-DD", Locale.KOREA)
override fun getFormattedValue(value: Float): String? {
val millis =
TimeUnit.HOURS.toMillis(value.toLong())
return mFormat.format(Date(millis))
}
})
val leftAxis3 = chart3!!.getAxisLeft()
leftAxis3.setPosition(YAxis.YAxisLabelPosition.INSIDE_CHART)
leftAxis3.textColor = ColorTemplate.getHoloBlue()
leftAxis3.setDrawGridLines(true)
leftAxis3.isGranularityEnabled = true
leftAxis3.axisMinimum = 0f
leftAxis3.axisMaximum = 170f
leftAxis3.yOffset = -9f
leftAxis3.textColor = Color.rgb(255, 192, 56)
val rightAxis3 = chart3!!.getAxisRight()
rightAxis3.isEnabled = false
setData3()
}
private fun setData1() {
val entries = ArrayList<PieEntry>()
entries.add(
PieEntry(
20.0f, "",
resources.getDrawable(R.drawable.smile1_24)
)
)
entries.add(
PieEntry(
20.0f, "",
resources.getDrawable(R.drawable.smile2_24)
)
)
entries.add(
PieEntry(
20.0f, "",
resources.getDrawable(R.drawable.smile3_24)
)
)
entries.add(
PieEntry(
20f, "",
resources.getDrawable(R.drawable.smile4_24)
)
)
entries.add(
PieEntry(
20.0f, "",
resources.getDrawable(R.drawable.smile5_24)
)
)
val dataSet = PieDataSet(entries, "기분별 비율")
dataSet.setDrawIcons(true)
dataSet.sliceSpace = 3f
dataSet.iconsOffset = MPPointF(0F, (-40).toFloat())
dataSet.selectionShift = 5f
val colors = ArrayList<Int>()
for (c in ColorTemplate.JOYFUL_COLORS) {
colors.add(c)
}
dataSet.colors = colors
val data = PieData(dataSet)
data.setValueTextSize(22.0f)
data.setValueTextColor(Color.WHITE)
chart!!.data = data
chart!!.invalidate()
}
private fun setData2() {
val entries = ArrayList<BarEntry>()
entries.add(
BarEntry(
1.0f, 20.0f,
resources.getDrawable(R.drawable.smile1_24)
)
)
entries.add(
BarEntry(
2.0f, 40.0f,
resources.getDrawable(R.drawable.smile2_24)
)
)
entries.add(
BarEntry(
3.0f, 60.0f,
resources.getDrawable(R.drawable.smile3_24)
)
)
entries.add(
BarEntry(
4.0f, 30.0f,
resources.getDrawable(R.drawable.smile4_24)
)
)
entries.add(
BarEntry(
5.0f, 90.0f,
resources.getDrawable(R.drawable.smile5_24)
)
)
val dataSet2 = BarDataSet(entries, "Sinus Function")
dataSet2.color = Color.rgb(240, 120, 124)
val colors = ArrayList<Int>()
for (c in ColorTemplate.JOYFUL_COLORS) {
colors.add(c)
}
dataSet2.colors = colors
dataSet2.iconsOffset = MPPointF(0F, (-10).toFloat())
val data = BarData(dataSet2)
data.setValueTextSize(10f)
data.setDrawValues(false)
data.barWidth = 0.8f
chart2!!.data = data
chart2!!.invalidate()
}
private fun setData3() {
val values =
ArrayList<Entry>()
values.add(Entry(24f, 20.0f))
values.add(Entry(48f, 50.0f))
values.add(Entry(72f, 30.0f))
values.add(Entry(96f, 70.0f))
values.add(Entry(120f, 90.0f))
// create a dataset and give it a type
val set1 = LineDataSet(values, "DataSet 1")
set1.axisDependency = YAxis.AxisDependency.LEFT
set1.color = ColorTemplate.getHoloBlue()
set1.valueTextColor = ColorTemplate.getHoloBlue()
set1.lineWidth = 1.5f
set1.setDrawCircles(true)
set1.setDrawValues(false)
set1.fillAlpha = 65
set1.fillColor = ColorTemplate.getHoloBlue()
set1.highLightColor = Color.rgb(244, 117, 117)
set1.setDrawCircleHole(false)
// create a data object with the data sets
val data = LineData(set1)
data.setValueTextColor(Color.WHITE)
data.setValueTextSize(9f)
// set data
chart3!!.data = data
chart3!!.invalidate()
}
}
MPAndroidChart 라이브러리 코드를 참고하였음
통계 화면 완성