Android安卓实战项目(11)—每个步骤带有动画演示功能的线上运动APP,可计算每日运动卡路里(源码在文末🐕🐕🐕)
【bilibili演示】
https://www.bilibili.com/video/BV1bk4y1g7Wo/?share_source=copy_web&vd_source=b2e9b9ed746acda34f499009647748ed
一.项目运行介绍
主页面
每日卡路里记录
进行运动—1
运动(1)后卡路里记录展示
右上角提示窗口
二.具体实现
MainActivity.java
package com.team.sportsskuyy;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.getkeepsafe.taptargetview.TapTarget;
import com.google.android.material.snackbar.Snackbar;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.Map;
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private CardView kalori,easy,medium,expert;
private DatabaseReference mDatabase;
String all;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//Definisi Text And Image
final ImageView imageView = findViewById(R.id.dokumentasi);
final ImageView hapus = findViewById(R.id.delkalori);
final TextView mTotal = findViewById(R.id.mTotal);
//Definisi Kartu Pada Layout
kalori = (CardView) findViewById(R.id.kalori);
easy = (CardView) findViewById(R.id.mudah);
medium = (CardView) findViewById(R.id.sedang);
expert = (CardView) findViewById(R.id.sulit);
//Click Listener Pada Kartu
kalori.setOnClickListener(this);
easy.setOnClickListener(this);
medium.setOnClickListener(this);
expert.setOnClickListener(this);
imageView.setOnClickListener(this);
//Definisi Firebase
mDatabase = FirebaseDatabase.getInstance().getReference().child("latihan");
hapus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDatabase.setValue(null);
mTotal.setText("0");
Snackbar.make(findViewById(R.id.delkalori),"Berhasil menghapus semua kalori",Snackbar.LENGTH_LONG).show();
}
});
//Sum Kalori
mDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
int sum = 0;
for(DataSnapshot ds : dataSnapshot.getChildren()){
Map<String,Object> map = (Map<String,Object>) ds.getValue();
assert map != null;
Object kal = map.get("kalori");
int pValue = Integer.parseInt(String.valueOf(kal));
sum += pValue;
mTotal.setText(String.valueOf(sum));
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
// Tap Target
TapTargetView.showFor(this, // `this` is an Activity
TapTarget.forView(findViewById(R.id.dokumentasi), "Baca Tutorialnya\nDisini")
// All options below are optional
.outerCircleColor(R.color.emerald) // Specify a color for the outer circle
.outerCircleAlpha(0.96f) // Specify the alpha amount for the outer circle
.targetCircleColor(R.color.white) // Specify a color for the target circle
.titleTextSize(22) // Specify the size (in sp) of the title text
.textColor(R.color.white) // Specify a color for both the title and description text
.dimColor(R.color.midnightblue) // If set, will dim behind the view with 30% opacity of the given color
.drawShadow(true) // Whether to draw a drop shadow or not
.cancelable(false) // Whether tapping outside the outer circle dismisses the view
.tintTarget(true) // Whether to tint the target view's color
.transparentTarget(false) // Specify whether the target is transparent (displays the content underneath)
.targetRadius(60), // Specify the target radius (in dp)
new TapTargetView.Listener() { // The listener can listen for regular clicks, long clicks or cancels
@Override
public void onTargetClick(TapTargetView view) {
super.onTargetClick(view); // This call is optional
}
});
}
@Override
public void onClick(View v) {
Intent i;
switch (v.getId()){
case R.id.kalori : i = new Intent(this,Kalori.class);startActivity(i); break;
case R.id.mudah : i = new Intent(this, EasyStepper.class);startActivity(i); break;
case R.id.sedang : i = new Intent(this, MediumStepper.class);startActivity(i); break;
case R.id.sulit : i = new Intent(this, ExpertStepper.class);startActivity(i); break;
case R.id.dokumentasi : i = new Intent(this, Dokumentasi.class);startActivity(i); break;
default:break;
}
}
}
这段代码是一个Android应用程序的主活动(MainActivity),它实现了一个简单的健身应用界面。下面逐行解释代码的各个部分:
package com.team.sportsskuyy;
这一行是指定Java文件的包名。
import android.content.Intent;
import android.os.Bundle;
import android.view.View;
import android.widget.ImageView;
import android.widget.TextView;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.cardview.widget.CardView;
import com.getkeepsafe.taptargetview.TapTargetView;
import com.getkeepsafe.taptargetview.TapTarget;
import com.google.android.material.snackbar.Snackbar;
import com.google.firebase.database.DataSnapshot;
import com.google.firebase.database.DatabaseError;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import com.google.firebase.database.ValueEventListener;
import java.util.Map;
这些是引入所需的Android类和库。
public class MainActivity extends AppCompatActivity implements View.OnClickListener {
这个类是MainActivity,它扩展自AppCompatActivity,并且实现了View.OnClickListener接口,以便处理视图的点击事件。
private CardView kalori, easy, medium, expert;
private DatabaseReference mDatabase;
String all;
这里声明了一些成员变量,包括用于卡片视图(CardView)的引用,Firebase数据库的引用,以及一个字符串变量。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
这是活动的创建方法。它设置了活动的布局,该布局在"res/layout"目录下的"activity_main.xml"文件中定义。
final ImageView imageView = findViewById(R.id.dokumentasi);
final ImageView hapus = findViewById(R.id.delkalori);
final TextView mTotal = findViewById(R.id.mTotal);
这里初始化了几个ImageView和一个TextView,通过它们可以找到布局中对应的视图。
kalori = (CardView) findViewById(R.id.kalori);
easy = (CardView) findViewById(R.id.mudah);
medium = (CardView) findViewById(R.id.sedang);
expert = (CardView) findViewById(R.id.sulit);
这些代码初始化了卡片视图(CardView)的引用,它们分别与布局中的id为"kalori"、“mudah”、"sedang"和"sulit"的卡片视图相关联。
kalori.setOnClickListener(this);
easy.setOnClickListener(this);
medium.setOnClickListener(this);
expert.setOnClickListener(this);
imageView.setOnClickListener(this);
为卡片视图和ImageView设置点击监听器,当它们被点击时,会触发onClick方法。
mDatabase = FirebaseDatabase.getInstance().getReference().child("latihan");
这里初始化了Firebase数据库的引用,它指向一个名为"latihan"的数据集。
hapus.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
mDatabase.setValue(null);
mTotal.setText("0");
Snackbar.make(findViewById(R.id.delkalori), "Berhasil menghapus semua kalori", Snackbar.LENGTH_LONG).show();
}
});
这是一个点击监听器,当"hapus"视图被点击时,它会在Firebase数据库中设置为null,然后将文本视图"mTotal"的文本设置为"0",最后显示一个Snackbar提示。
mDatabase.addValueEventListener(new ValueEventListener() {
@Override
public void onDataChange(@NonNull DataSnapshot dataSnapshot) {
int sum = 0;
for(DataSnapshot ds : dataSnapshot.getChildren()){
Map<String, Object> map = (Map<String, Object>) ds.getValue();
assert map != null;
Object kal = map.get("kalori");
int pValue = Integer.parseInt(String.valueOf(kal));
sum += pValue;
mTotal.setText(String.valueOf(sum));
}
}
@Override
public void onCancelled(@NonNull DatabaseError databaseError) {
}
});
这是Firebase数据库的值事件监听器,当数据发生变化时,它会遍历数据快照(DataSnapshot)中的子项,并将其中的"kalori"值累加到"sum"变量中,然后将"sum"值显示在"mTotal"文本视图中。
TapTargetView.showFor(this, TapTarget.forView(findViewById(R.id.dokumentasi), "Baca Tutorialnya\nDisini")
// ...(一些设置略去)
这是用于显示TapTargetView的代码,它用于展示一个用户引导提示。它会在"imageView"视图上显示一个圆形引导,带有一些自定义的视觉设置。
@Override
public void onClick(View v) {
Intent i;
switch (v.getId()){
case R.id.kalori : i = new Intent(this, Kalori.class); startActivity(i); break;
case R.id.mudah : i = new Intent(this, EasyStepper.class); startActivity(i); break;
case R.id.sedang : i = new Intent(this, MediumStepper.class); startActivity(i); break;
case R.id.sulit : i = new Intent(this, ExpertStepper.class); startActivity(i); break;
case R.id.dokumentasi : i = new Intent(this, Dokumentasi.class); startActivity(i); break;
default:break;
}
}
这是点击监听器的实现方法。根据被点击的视图ID,它会启动不同的活动(Activity),这些活动分别是"Kalori"、“EasyStepper”、“MediumStepper”、“ExpertStepper"和"Dokumentasi”。根据所点击的不同视图,会有不同的操作。
MediumStepper.java
package com.team.sportsskuyy;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import io.victoralbertos.breadcumbs_view.BreadcrumbsView;
import pl.droidsonroids.gif.GifImageView;
public class MediumStepper extends AppCompatActivity {
DatabaseReference databaseLatihan;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_medium_stepper);
//Definisi firebase
databaseLatihan = FirebaseDatabase.getInstance().getReference("latihan");
// Definisi Gif
final GifImageView anim = (GifImageView) findViewById(R.id.gif);
// Definisi Breadcrumbs
final BreadcrumbsView lanjot = (BreadcrumbsView) findViewById(R.id.breadcrumbs);
// Definisi TextView
final TextView keterangan = (TextView) findViewById(R.id.tulisan);
// Definisi Button
final Button button = (Button) findViewById(R.id.Lanjutes);
final Button nyerah = (Button) findViewById(R.id.nyerahex);
// Mengubah title
this.setTitle("Latihan Sedang");
// Hidden button first time
nyerah.setVisibility(View.INVISIBLE);
nyerah.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog();
}
});
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// Timer
new CountDownTimer(3000,1000){
@Override
public void onFinish() {
button.setVisibility(View.VISIBLE);
}
@Override
public void onTick(long millisUntilFinished) {
button.setVisibility(View.INVISIBLE);
}
}.start();
// Change Kabeh
if (button.getText() == "SELESAI"){
button.setText("Keluar");
keterangan.setText("Latihan Telah Selesai");
anim.setImageResource(R.drawable.ic_trophy);
nyerah.setVisibility(View.INVISIBLE);
lanjot.nextStep();
}else if(button.getText() == "Keluar"){
MediumStepper.this.finish();
}else if(button.getText() == "Lanjut Langkah Ke 2"){
button.setText("Lanjut Langkah Ke 3");
anim.setImageResource(R.drawable.highkneeup);
keterangan.setText("Lakukan High Knee Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("High Knee Up",45);
}else if(button.getText() == "Lanjut Langkah Ke 3"){
button.setText("Lanjut Langkah Ke 4");
anim.setImageResource(R.drawable.mountainclimber);
keterangan.setText("Lakukan Mountain Climbers\nselama 45 detik");
lanjot.nextStep();
addLatihan("Mountain Climbers",45);
}else if(button.getText() == "Lanjut Langkah Ke 4"){
button.setText("Istirahat Pertama");
anim.setImageResource(R.drawable.situp);
keterangan.setText("Lakukan Sit Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("Sit Up",30);
}else if(button.getText() == "Istirahat Pertama"){
button.setText("Lanjut Langkah Ke 6");
anim.setImageResource(R.drawable.ic_break);
keterangan.setText("Istirahat dahulu\nselama 20 detik");
lanjot.nextStep();
}else if(button.getText() == "Lanjut Langkah Ke 6"){
button.setText("Lanjut Langkah Ke 7");
anim.setImageResource(R.drawable.plankknee);
keterangan.setText("Lakukan Plank Knee Twist\nselama 45 detik");
lanjot.nextStep();
addLatihan("Plank Knee Twist",40);
}else if(button.getText() == "Lanjut Langkah Ke 7"){
button.setText("Lanjut Langkah Ke 8");
anim.setImageResource(R.drawable.widepushup);
keterangan.setText("Lakukan Wide Push Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("Wide Push Up",30);
}else if(button.getText() == "Lanjut Langkah Ke 8"){
button.setText("Lanjut Langkah Ke 9");
anim.setImageResource(R.drawable.crunch);
keterangan.setText("Lakukan Crunch\nselama 45 detik");
lanjot.nextStep();
addLatihan("Crunch",25);
}else if(button.getText() == "Lanjut Langkah Ke 9"){
button.setText("Istirahat Kedua");
anim.setImageResource(R.drawable.pushup);
keterangan.setText("Lakukan Push Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("Push Up",25);
}else if(button.getText() == "Istirahat Kedua"){
button.setText("Lanjut Langkah Ke 10");
anim.setImageResource(R.drawable.ic_break);
keterangan.setText("Istirahat dahulu\nselama 20 detik");
lanjot.nextStep();
}else if(button.getText() == "Lanjut Langkah Ke 10"){
button.setText("Lanjut Langkah Ke 11");
anim.setImageResource(R.drawable.russiantwist);
keterangan.setText("Lakukan Russian Twist\nselama 45 detik");
lanjot.nextStep();
addLatihan("Russin Twist",25);
}else if(button.getText() == "Lanjut Langkah Ke 11"){
button.setText("Lanjut Langkah Ke 12");
anim.setImageResource(R.drawable.burpeess);
keterangan.setText("Lakukan Burpees\nselama 45 detik");
lanjot.nextStep();
addLatihan("Burpess",60);
}else if(button.getText() == "Lanjut Langkah Ke 12"){
button.setText("Lanjut Langkah Ke 13");
anim.setImageResource(R.drawable.toejump);
keterangan.setText("Lakukan Toe Jump\nselama 45 detik");
lanjot.nextStep();
addLatihan("Toe Jump",30);
}else if(button.getText() == "Lanjut Langkah Ke 13"){
button.setText("Lanjut Langkah Ke 14");
anim.setImageResource(R.drawable.plank);
keterangan.setText("Lakukan Plank\nselama 45 detik");
lanjot.nextStep();
addLatihan("Plank",55);
}else if(button.getText() == "Lanjut Langkah Ke 14"){
button.setText("Istirahat Ketiga");
anim.setImageResource(R.drawable.squat);
keterangan.setText("Lakukan Squat\nselama 45 detik");
lanjot.nextStep();
addLatihan("Squat",35);
}else if(button.getText() == "Istirahat Ketiga"){
button.setText("Lanjut Langkah Ke 15");
anim.setImageResource(R.drawable.ic_break);
keterangan.setText("Istirahat dahulu\nselama 20 detik");
lanjot.nextStep();
}else if(button.getText() == "Lanjut Langkah Ke 15"){
button.setText("Lanjut Langkah Ke 16");
anim.setImageResource(R.drawable.situp);
keterangan.setText("Lakukan Sit Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("Sit Up",30);
}else if(button.getText() == "Lanjut Langkah Ke 16"){
button.setText("Lanjut Langkah Ke 17");
anim.setImageResource(R.drawable.pushup);
keterangan.setText("Lakukan Push Up\nselama 45 detik");
lanjot.nextStep();
addLatihan("Push Up",30);
}else if(button.getText() == "Lanjut Langkah Ke 17"){
button.setText("SELESAI");
anim.setImageResource(R.drawable.jumpingjacks);
keterangan.setText("Lakukan Jumping Jack\nselama 45 detik");
lanjot.nextStep();
addLatihan("Jumping Jacks",50);
} else {
button.setText("Lanjut Langkah Ke 2");
nyerah.setVisibility(View.VISIBLE);
anim.setImageResource(R.drawable.jumpingjacks);
keterangan.setText("Lakukan Jumping Jacks\nselama 45 detik");
addLatihan("Jumping Jacks", 45);
lanjot.nextStep();
}
}
});
}
public void addLatihan(String gerakan, int kalori) {
DateFormat dateFormat = new SimpleDateFormat("HH:mm:ss dd/MM/yyyy");
Date date = new Date();
String id_latihan = databaseLatihan.push().getKey();
String tanggal = dateFormat.format(date);
int jumlah_kalori = 605;
addFirebase save = new addFirebase(id_latihan, tanggal, gerakan, kalori);
databaseLatihan.child(id_latihan).setValue(save);
}
public void onBackPressed(){
showDialog();
}
private void showDialog(){
AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(
this);
// set title dialog
alertDialogBuilder.setTitle("Informasi");
// set pesan dari dialog
alertDialogBuilder
.setMessage("Apakah Anda yakin mau berhenti?\nudah latihan loh!")
.setIcon(R.mipmap.icons)
.setCancelable(false)
.setPositiveButton("Ya",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog,int id) {
// jika tombol diklik, maka akan menutup activity ini
MediumStepper.this.finish();
}
})
.setNegativeButton("Tidak",new DialogInterface.OnClickListener() {
public void onClick(DialogInterface dialog, int id) {
// jika tombol ini diklik, akan menutup dialog
// dan tidak terjadi apa2
dialog.cancel();
}
});
// membuat alert dialog dari builder
AlertDialog alertDialog = alertDialogBuilder.create();
// menampilkan alert dialog
alertDialog.show();
}
}
这段代码是一个 Android 应用程序,用于实现一个健身计划的应用。下面逐行解释代码的主要部分:
package com.team.sportsskuyy;
这行代码声明了 Java 包的名称,它是这个应用程序的命名空间。
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.CountDownTimer;
import android.os.Bundle;
import android.view.View;
import android.widget.Button;
import android.widget.TextView;
这些是导入所需的 Android 类。AlertDialog
用于显示对话框,CountDownTimer
用于实现倒计时,Bundle
是用于存储活动状态信息的容器,View
用于视图操作,Button
是按钮控件,TextView
是文本显示控件。
import androidx.appcompat.app.AppCompatActivity;
这里导入了 AppCompatActivity
类,用于创建一个 Android 活动。
import com.google.firebase.database.DatabaseReference;
import com.google.firebase.database.FirebaseDatabase;
这两行导入了与 Firebase 数据库相关的类,用于与实时数据库进行交互。
import io.victoralbertos.breadcumbs_view.BreadcrumbsView;
import pl.droidsonroids.gif.GifImageView;
这里导入了两个自定义库的类,分别是用于显示面包屑导航的 BreadcrumbsView
和用于显示 GIF 图像的 GifImageView
。
public class MediumStepper extends AppCompatActivity {
这是一个名为 MediumStepper
的类,继承自 AppCompatActivity
,表示一个 Android 活动。
DatabaseReference databaseLatihan;
声明了一个 DatabaseReference
类型的变量 databaseLatihan
,用于与 Firebase 数据库建立连接。
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_medium_stepper);
onCreate
方法是 Android 活动的生命周期方法之一,用于在活动创建时执行。这里通过 setContentView
设置活动的布局,即 activity_medium_stepper.xml
。
databaseLatihan = FirebaseDatabase.getInstance().getReference("latihan");
这行代码初始化了 databaseLatihan
变量,指向 Firebase 数据库中的 “latihan” 节点。
final GifImageView anim = (GifImageView) findViewById(R.id.gif);
声明了一个 GifImageView
类型的变量 anim
,表示用于显示 GIF 图像的视图控件,通过 findViewById
方法找到布局文件中 R.id.gif
对应的视图。
final BreadcrumbsView lanjot = (BreadcrumbsView) findViewById(R.id.breadcrumbs);
声明了一个 BreadcrumbsView
类型的变量 lanjot
,表示用于显示面包屑导航的视图控件,通过 findViewById
方法找到布局文件中 R.id.breadcrumbs
对应的视图。
final TextView keterangan = (TextView) findViewById(R.id.tulisan);
声明了一个 TextView
类型的变量 keterangan
,表示用于显示文本的视图控件,通过 findViewById
方法找到布局文件中 R.id.tulisan
对应的视图。
final Button button = (Button) findViewById(R.id.Lanjutes);
final Button nyerah = (Button) findViewById(R.id.nyerahex);
声明了两个 Button
类型的变量 button
和 nyerah
,分别表示两个按钮控件,通过 findViewById
方法找到布局文件中对应的视图。
this.setTitle("Latihan Sedang");
设置活动的标题为 “Latihan Sedang”。
nyerah.setVisibility(View.INVISIBLE);
将 nyerah
按钮的可见性设置为不可见。
nyerah.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
showDialog();
}
});
为 nyerah
按钮设置点击事件监听器,当按钮被点击时,调用 showDialog()
方法显示对话框。
button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
// ...
// 这里是按钮点击事件的处理逻辑,根据按钮的文本不同执行不同的操作
// ...
}
});
为 button
按钮设置点击事件监听器,当按钮被点击时,执行按钮点击事件的处理逻辑。
public void addLatihan(String gerakan, int kalori) {
// ...
// 这是一个自定义方法,用于将健身信息添加到 Firebase 数据库中
// ...
}
addLatihan
方法用于将健身信息添加到 Firebase 数据库中,包括运动名称和消耗的卡路里数。
public void onBackPressed(){
showDialog();
}
重写了 onBackPressed
方法,当用户按下返回按钮时,调用 showDialog()
方法显示对话框。
private void showDialog(){
// ...
// 这是一个自定义方法,用于显示一个确认对话框
// ...
}
showDialog
方法用于显示一个确认对话框,询问用户是否确定要退出。
总体来说,这段代码实现了一个健身计划应用,用户可以在不同的健身步骤之间切换,计时每个动作,将健身信息存储到 Firebase 数据库,并提供了退出确认的对话框。
三.项目源码
项目已开源:
链接:https://pan.baidu.com/s/1wXGLjL0C8Zf3XkeImaWthQ?pwd=jynl
提取码:jynl
创作不易(可做实验报告,代码讲解等)
请私信作者或
(v)15135757306