Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- // Edistynyt mobiiliohjelmointi, 4.5.2023
- // kolmannen osapuolen komponentit,
- // SpinKit:
- https://github.com/ybq/Android-SpinKit
- Jos kokeillaan importata suoraan projektiin, tulee virhe, koska Android Studio ei löydä pluginia:
- implementation 'com.github.ybq:Android-SpinKit:1.4.0'
- // tämä korjaantuu sillä, että lisätään settings.gradle -tiedostoon molempiin repositoryihin jitpack-viittaus, eli:
- maven { url "https://jitpack.io" }
- eli koko tiedosto (paitsi pohjalla olevat projektin nimet ym.):
- pluginManagement {
- repositories {
- google()
- mavenCentral()
- gradlePluginPortal()
- maven { url "https://jitpack.io" }
- }
- }
- dependencyResolutionManagement {
- repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
- repositories {
- google()
- mavenCentral()
- maven { url "https://jitpack.io" }
- }
- }
- // kokeillaan esim. fragment_homen ulkoasussa:
- <com.github.ybq.android.spinkit.SpinKitView
- android:id="@+id/spin_kit"
- style="@style/SpinKitView.Large.Circle"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="center"
- app:SpinKit_Color="#E18835DC"
- app:layout_constraintBottom_toBottomOf="parent"
- app:layout_constraintEnd_toEndOf="parent"
- app:layout_constraintStart_toStartOf="parent"
- app:layout_constraintTop_toBottomOf="@+id/text_home" />
- // jos on tarve koodissa piilottaa latausanimaatio, voidaan tehdä esim. näin:
- binding.spinKit.visibility = View.GONE
- // tehdään seuraavaksi uusi fragment: CustomViewTesterFragment, lisätään päävalikkoon ja otetaan binding layer käyttöön
- // esim.
- class CustomViewTesterFragment : Fragment() {
- private var _binding: FragmentCustomViewTesterBinding? = null
- // This property is only valid between onCreateView and
- // onDestroyView.
- private val binding get() = _binding!!
- override fun onCreateView(
- inflater: LayoutInflater,
- container: ViewGroup?,
- savedInstanceState: Bundle?
- ): View? {
- _binding = FragmentCustomViewTesterBinding.inflate(inflater, container, false)
- val root: View = binding.root
- return root
- }
- override fun onDestroyView() {
- super.onDestroyView()
- _binding = null
- }
- }
- // seuraavaksi testataan tätä pluginia (tässä uudessa fragmentissa):
- https://github.com/anastr/SpeedView
- // muokataan CustomViewTesterFragmentin ulkoasuksi LinearLayout helpomman testaamisen vuoksi:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- android:orientation="vertical"
- tools:context=".CustomViewTesterFragment">
- </LinearLayout>
- // lisätään SpeedViewin import kuntoon gradlessa:
- implementation 'com.github.anastr:speedviewlib:1.6.0'
- // kokeillaan nyt lisätä SpeedView ulkoasuun LinearLayoutin sisälle:
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="20dp" />
- // kokeillaan vaihtaa nopeus koodissa:
- // kokeillaan nostaa npoeus 35:een
- binding.speedView.speedTo(35f)
- // otetaan tremble-ominaisuus pois, ja muokataan LinearLayoutin XML:ää siten, että sieltä löytyy myös app-määritelmä:
- // tämän avulla voimme muokata SpeedViewin ominaisuuksia suoraan XML:n kautta:
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent"
- xmlns:app="http://schemas.android.com/apk/res-auto"
- android:orientation="vertical"
- tools:context=".CustomViewTesterFragment">
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- app:sv_withTremble="false"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="20dp" />
- </LinearLayout>
- // muokataan lisää ominaisuuksia, vaihdetaan yksikkö Celsiukseen, ja alaraja -50 ja yläraja +50
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView"
- app:sv_withTremble="false"
- app:sv_minSpeed="-50"
- app:sv_maxSpeed="50"
- app:sv_unit="℃"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="20dp" />
- // kokeillaan esim. säädatalla (MQTT aiemmin)
- <com.github.anastr.speedviewlib.SpeedView
- android:id="@+id/speedView_temperature"
- app:sv_withTremble="false"
- app:sv_minSpeed="-50"
- app:sv_maxSpeed="50"
- app:sv_unit="℃"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_margin="20dp" />
- // ja kytketään data binding layerin kautta,
- activity?.runOnUiThread {
- binding.textViewWeatherText.text = text
- binding.speedViewTemperature.speedTo(temperature.toFloat())
- }
- // kokeillaan vielä kalenteria hieman:
- https://github.com/npanigrahy/Custom-Calendar-View
- // tehdään uusi fragment, esim. CalendarFragment, ja lisätään päävalikkoon
- // uusi import gradleen:
- implementation 'com.github.npanigrahy:Custom-Calendar-View:v1.1'
- // ulkoasuun:
- <com.stacktips.view.CustomCalendarView
- android:id="@+id/calendar_view"
- android:layout_width="match_parent"
- android:layout_height="wrap_content"
- android:background="#ffffff">
- </com.stacktips.view.CustomCalendarView>
- // muunnettuna Java-koodi Kotliniksi:
- //Initialize calendar with date
- val currentCalendar: Calendar = Calendar.getInstance(Locale.getDefault())
- //Show Monday as first date of week
- binding.calendarView.setFirstDayOfWeek(Calendar.MONDAY)
- //Show/hide overflow days of a month
- binding.calendarView.setShowOverflowDate(false)
- //call refreshCalendar to update calendar the view
- binding.calendarView.refreshCalendar(currentCalendar)
- //Handling custom calendar events
- binding.calendarView.setCalendarListener(object : CalendarListener {
- override fun onDateSelected(date: Date?) {
- val df = SimpleDateFormat("dd-MM-yyyy")
- Toast.makeText(activity, df.format(date), Toast.LENGTH_SHORT).show()
- }
- override fun onMonthChanged(date: Date?) {
- val df = SimpleDateFormat("MM-yyyy")
- Toast.makeText(activity, df.format(date), Toast.LENGTH_SHORT).show()
- }
- })
- // Omien custom viewien tekeminen, versio 1, Täysin oma custom view alusta asti
- Tehdään uusi luokka projektiin (Kotlin class) => CustomTemperatureView
- , Muokataan sisälle perusrunko CustomViewistä ilman ylimääräisiä funktioita:
- class CustomTemperatureView @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
- ) : View(context, attrs, defStyleAttr) {
- // your helper variables etc. can be here
- init
- {
- // this is constructor of your component
- // all initializations go here
- }
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
- // here you can do all the drawing
- }
- override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- // Android uses this to determine the exact size of your component on screen
- }
- }
- // kokeillaan asettaa värejä ja myös ympyrää ja tekstiä:
- class CustomTemperatureView @JvmOverloads constructor(
- context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
- ) : View(context, attrs, defStyleAttr) {
- // your helper variables etc. can be here
- private val paint = Paint(Paint.ANTI_ALIAS_FLAG)
- private val textPaint = Paint(Paint.ANTI_ALIAS_FLAG)
- init
- {
- // this is constructor of your component, all initializations go here
- // define the colors!
- paint.color = Color.BLUE
- textPaint.color = Color.BLACK
- }
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
- // here you can do all the drawing
- // you can do all the drawing through the canvas-object
- // parameters: x-coordinate, y-coordinate, size, color
- canvas.drawCircle(0f, 0f, 100f, paint)
- // parameters: content, x, y, color
- canvas.drawText("Test!", 10f, 10f, textPaint);
- }
- override fun onMeasure(widthMeasureSpec : Int, heightMeasureSpec : Int){
- super.onMeasure(widthMeasureSpec, heightMeasureSpec)
- // Android uses this to determine the exact size of your component on screen
- }
- }
- // kokeillaan lisätä tämä CustomView tässä vaiheessa ulkoasuun, esim. CustomViewTesterFragment:
- <com.example.edistynytandroid2023verkko.CustomTemperatureView
- android:layout_width="match_parent"
- android:layout_height="600dp"
- android:layout_margin="20dp" />
- Huom, paketin nimi on projektissasi eri kuin ohjaajalla
- Ympyrä on näytöllä vielä melko sekavan näköinen, joten lisää tarvitsee koodia vielä.
- Ihannetilanteessa Custom View pystyy itse päättelemään oikeat mittasuhteet, koordinaatit ja koot suoraan XML:ssä annetun tiedon perusteella. Esim. width ja height jos olisivat 200dp:
- <com.example.edistynytandroid2023verkko.CustomTemperatureView
- android:layout_width="200dp"
- android:layout_height="200dp"
- android:layout_margin="20dp" />
- Oletuksena Custom View ei tiedä näistä kokotiedoista mitään, vaan piirtää aina tasan sen mitä sinne on koodattu. Jotta XML:ssä olevat koot saadaan CustomViewin käyttöön, pitää meidän tehdä onMeasure sillä tavalla, että Android mittaa tietojen perusteella CustomViewin oikean koon näytöllä:
- // tämän CustomViewin oletuskoko, 200 x 200
- val size = 200
- override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
- // Try for a width based on our minimum
- val minw: Int = paddingLeft + paddingRight + suggestedMinimumWidth
- var w: Int = View.resolveSizeAndState(minw, widthMeasureSpec, 1)
- // if no exact size given (either dp or match_parent)
- // use this one instead as default (wrap_content)
- if (w == 0)
- {
- w = size * 2
- }
- // Whatever the width ends up being, ask for a height that would let the view
- // get as big as it can
- // val minh: Int = View.MeasureSpec.getSize(w) + paddingBottom + paddingTop
- // in this case, we use the height the same as our width, since it's a circle
- val h: Int = View.resolveSizeAndState(
- View.MeasureSpec.getSize(w),
- heightMeasureSpec,
- 0
- )
- setMeasuredDimension(w, h)
- }
- // tämän jälkeen voimme hyödyntää width-muuttujaa onDrawissa. ilman onMeasurea width-muuttuja on aina 0, minkä takia tämä ei suoraan toimi.
- init
- {
- // this is constructor of your component, all initializations go here
- // define the colors!
- paint.color = Color.BLUE
- textPaint.color = Color.WHITE
- textPaint.textSize = 70f
- textPaint.textAlign = Paint.Align.CENTER
- }
- override fun onDraw(canvas: Canvas) {
- super.onDraw(canvas)
- // here you can do all the drawing
- // you can do all the drawing through the canvas-object
- // parameters: x-coordinate, y-coordinate, size, color
- canvas.drawCircle(width.toFloat() / 2, width.toFloat() / 2, width.toFloat() / 2, paint)
- // parameters: content, x, y, color
- // pieni 30px offset lisätty y-akseliin, jotta teksti on keskempänä näyttöä
- canvas.drawText("Test!", width.toFloat() / 2, width.toFloat() / 2 + 30, textPaint);
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement