Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中

Android安卓实战项目(10)—详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中

【bilibili演示】
https://www.bilibili.com/video/BV1iz4y1p7jS/?share_source=copy_web&vd_source=b2e9b9ed746acda34f499009647748ed

一.项目运行介绍

app—logo

image-20230807180647917

主页

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第1张图片

添加餐食

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第2张图片

餐食分类

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第3张图片

对已有的餐食进行添加

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第4张图片

添加新的餐食

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第5张图片

查看今日餐食

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第6张图片

对今日的餐食进行详细的概览

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第7张图片

产看之前的餐食信息

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第8张图片

每日目标界面

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第9张图片

每日锻炼进行增加

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第10张图片

控件选择

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第11张图片

编辑锻炼计划

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第12张图片

编辑锻炼日程

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第13张图片

编辑锻炼

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第14张图片

源码概览

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第15张图片

Android安卓实战项目(10)---详细记录饮食与训练计划App【大Demo】可记录每日消耗和数据面板(源码在文末)可用于比赛项目或者作业参考中_第16张图片

二.具体实现

Activity_Main.java
package com.falyrion.gymtonicapp;

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;

import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.view.MenuItem;

import com.falyrion.gymtonicapp.data.DatabaseHelper;
import com.falyrion.gymtonicapp.fragments.Fragment_Nutrition;
import com.falyrion.gymtonicapp.fragments.Fragment_Workout;
import com.falyrion.gymtonicapp.fragments.Fragment_Settings;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;

import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

public class Activity_Main extends AppCompatActivity {

    public String date;
    private int currentFragmentID = 0;
    public DatabaseHelper databaseHelper;


    private void setFragmentFood(String date) {
        Fragment_Nutrition fragment = new Fragment_Nutrition();
        Bundle args = new Bundle();
        args.putString("date", date);
        fragment.setArguments(args);
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
    }

    private void setFragmentBodyStats() {
        // Pass
    }

    private void setFragmentWorkout() {
        Fragment_Workout fragment = new Fragment_Workout();
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
    }

    private void setFragmentSettings() {
        Fragment_Settings fragment = new Fragment_Settings();
        getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
    }

    private static void updateLanguage(Context context, String language) {

        if (language.equals("system")) {
            return;
        }

        Locale locale = new Locale(language);
        Locale.setDefault(locale);

        Resources resources = context.getResources();

        Configuration configuration = resources.getConfiguration();
        configuration.locale = locale;

        resources.updateConfiguration(configuration, resources.getDisplayMetrics());
    }


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // Database
        databaseHelper = new DatabaseHelper(Activity_Main.this);

        // Update language
        Cursor cursor = databaseHelper.getSettingsLanguage();
        if (cursor.getCount() > 0) {
            cursor.moveToFirst();
            updateLanguage(this, cursor.getString(0));
        }
        cursor.close();

        // -----------------------------------------------------------------------------------------
        // Get data if activity was started by another activity
        Intent intent = getIntent();

        // Get current date
        if (getIntent().hasExtra("date")) {
            date = intent.getStringExtra("date");
        } else {
            SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
            date = formatter.format(new Date());
        }

        // If there is a fragmentID submitted take it. Else keep previously set or default one (=0)
        if (getIntent().hasExtra("fragmentID")) {
            currentFragmentID = intent.getIntExtra("fragmentID", 0);
        }

        // Set current fragment based on fragmentID
        switch (currentFragmentID) {
            case 0:
                setFragmentFood(date);
                break;

            case 1:
                setFragmentBodyStats();
                break;

            case 2:
                setFragmentWorkout();
                break;

            case 3:
                setFragmentSettings();
                break;

            default:
                break;
        }

        // -----------------------------------------------------------------------------------------
        // Setup navigation bar
        BottomNavigationView navBar = findViewById(R.id.bottom_navigation);
        navBar.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
            @Override
            public boolean onNavigationItemSelected(@NonNull MenuItem item) {
                switch (item.getItemId()) {
                    case R.id.nav_bar_home:
                        if (currentFragmentID != 0) {
                            setFragmentFood(date);
                            currentFragmentID = 0;
                        }
                        return true;

                    case R.id.nav_bar_stats:
                        if (currentFragmentID != 1) {
                            setFragmentBodyStats();
                            currentFragmentID = 1;
                        }
                        return true;

                    case R.id.nav_bar_exersises:
                        if (currentFragmentID != 2) {
                            setFragmentWorkout();
                            currentFragmentID = 2;
                        }
                        return true;

                    case R.id.nav_bar_settings:
                        if (currentFragmentID != 3) {
                            setFragmentSettings();
                            currentFragmentID = 3;
                        }
                        return true;
                }
                return false;
            }
        });
    }

    @Override
    protected void onDestroy() {
        databaseHelper.close();
        super.onDestroy();
    }

}
package com.falyrion.gymtonicapp;

该代码所在的Java包名为com.falyrion.gymtonicapp

import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import android.content.Context;
import android.content.Intent;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.database.Cursor;
import android.os.Bundle;
import android.view.MenuItem;
import com.falyrion.gymtonicapp.data.DatabaseHelper;
import com.falyrion.gymtonicapp.fragments.Fragment_Nutrition;
import com.falyrion.gymtonicapp.fragments.Fragment_Workout;
import com.falyrion.gymtonicapp.fragments.Fragment_Settings;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

这部分是导入所需的类和库。其中包括AppCompatActivity(用于支持较旧的Android版本),以及其他一些用于处理数据库、日期和语言设置的类和库。

public class Activity_Main extends AppCompatActivity {

这里声明了一个名为Activity_Main的类,并让它继承自AppCompatActivity,即这是一个Android的活动(Activity)类。

public String date;
private int currentFragmentID = 0;
public DatabaseHelper databaseHelper;

在类的顶部,声明了一些成员变量。date是一个字符串,currentFragmentID是一个整数,默认值为0,databaseHelper是一个DatabaseHelper对象用于数据库操作。

private void setFragmentFood(String date) {
    Fragment_Nutrition fragment = new Fragment_Nutrition();
    Bundle args = new Bundle();
    args.putString("date", date);
    fragment.setArguments(args);
    getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
}

这是一个私有方法,用于设置显示Fragment_Nutrition(营养Fragment)。

  1. 创建一个Fragment_Nutrition的实例对象。
  2. 创建一个Bundle,并将当前日期(date)以"date"为键存入Bundle中。
  3. 将Bundle设置为Fragment的参数。
  4. 使用FragmentManager获取Fragment事务(FragmentTransaction)并将Fragment_Nutrition替换(replace)为activity_main.xml布局文件中指定ID为fragment_container的FrameLayout。
  5. 最后提交(commit)Fragment事务,完成Fragment的显示。
private void setFragmentBodyStats() {
    // Pass
}

这是一个私有方法,用于设置显示Fragment_BodyStats(身体统计Fragment)。但该方法没有实现任何具体的操作,即"// Pass"表示此处不执行任何代码。

private void setFragmentWorkout() {
    Fragment_Workout fragment = new Fragment_Workout();
    getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
}

这是一个私有方法,用于设置显示Fragment_Workout(训练Fragment)。

  1. 创建一个Fragment_Workout的实例对象。
  2. 使用FragmentManager获取Fragment事务(FragmentTransaction)并将Fragment_Workout替换为activity_main.xml布局文件中指定ID为fragment_container的FrameLayout。
  3. 最后提交(commit)Fragment事务,完成Fragment的显示。
private void setFragmentSettings() {
    Fragment_Settings fragment = new Fragment_Settings();
    getSupportFragmentManager().beginTransaction().replace(R.id.fragment_container, fragment).commit();
}

这是一个私有方法,用于设置显示Fragment_Settings(设置Fragment)。

  1. 创建一个Fragment_Settings的实例对象。
  2. 使用FragmentManager获取Fragment事务(FragmentTransaction)并将Fragment_Settings替换为activity_main.xml布局文件中指定ID为fragment_container的FrameLayout。
  3. 最后提交(commit)Fragment事务,完成Fragment的显示。
private static void updateLanguage(Context context, String language) {
    if (language.equals("system")) {
        return;
    }
    Locale locale = new Locale(language);
    Locale.setDefault(locale);
    Resources resources = context.getResources();
    Configuration configuration = resources.getConfiguration();
    configuration.locale = locale;
    resources.updateConfiguration(configuration, resources.getDisplayMetrics());
}

这是一个私有静态方法,用于更新应用程序的显示语言。

  1. 如果传入的language值为"system",则直接返回,不进行语言设置,保持系统默认语言。
  2. 创建一个新的Locale对象,根据传入的language值设定新的语言。
  3. 将新的Locale对象设定为应用程序的默认语言。
  4. 获取应用程序的资源(Resources)对象。
  5. 获取当前的配置信息(Configuration)对象,并将其语言设置为新的Locale。
  6. 使用更新后的配置信息更新应用程序的资源。
@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    // Database
    databaseHelper = new DatabaseHelper(Activity_Main.this);

    // Update language
    Cursor cursor = databaseHelper.getSettingsLanguage();
    if (cursor.getCount() > 0) {
        cursor.moveToFirst();
        updateLanguage(this, cursor.getString(0));
    }
    cursor.close();

    // -----------------------------------------------------------------------------------------
    // Get data if activity was started by another activity
    Intent intent = getIntent();

    // Get current date
    if (getIntent().hasExtra("date")) {
        date = intent.getStringExtra("date");
    } else {
        SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
        date = formatter.format(new Date());
    }

    // If there is a fragmentID submitted take it. Else keep previously set or default one (=0)
    if (getIntent().hasExtra("fragmentID")) {
        currentFragmentID = intent.getIntExtra("fragmentID", 0);
    }

    // Set current fragment based on fragmentID
    switch (currentFragmentID) {
        case 0:
            setFragmentFood(date);
            break;

        case 1:
            setFragmentBodyStats();
            break;

        case 2:
            setFragmentWorkout();
            break;

        case 3:
            setFragmentSettings();
            break;

        default:
            break;
    }

    // -----------------------------------------------------------------------------------------
    // Setup navigation bar
    BottomNavigationView navBar = findViewById(R.id.bottom_navigation);
    navBar.setOnItemSelectedListener(new NavigationBarView.OnItemSelectedListener() {
        @Override
        public boolean onNavigationItemSelected(@NonNull MenuItem item) {
            switch (item.getItemId()) {
                case R.id.nav_bar_home:
                    if (currentFragmentID != 0) {
                        setFragmentFood(date);
                        currentFragmentID = 0;
                    }
                   

 return true;

                case R.id.nav_bar_stats:
                    if (currentFragmentID != 1) {
                        setFragmentBodyStats();
                        currentFragmentID = 1;
                    }
                    return true;

                case R.id.nav_bar_exercises:
                    if (currentFragmentID != 2) {
                        setFragmentWorkout();
                        currentFragmentID = 2;
                    }
                    return true;

                case R.id.nav_bar_settings:
                    if (currentFragmentID != 3) {
                        setFragmentSettings();
                        currentFragmentID = 3;
                    }
                    return true;
            }
            return false;
        }
    });
}

这是Activity的主要方法,用于初始化Activity,并设置底部导航栏。

  1. 调用super.onCreate(savedInstanceState)来执行AppCompatActivity的onCreate()方法。
  2. 使用setContentView(R.layout.activity_main)指定显示的布局文件,即activity_main.xml。
  3. 初始化数据库:创建一个DatabaseHelper对象并关联到当前的Activity(Activity_Main.this)。
  4. 获取当前的语言设置并更新应用程序的显示语言。首先,从数据库中获取语言设置(使用getSettingsLanguage()方法),然后根据获取的设置调用updateLanguage()方法进行语言更新。
  5. 从上一个Activity传递的Intent中获取数据:
    • 如果Intent中包含名为"date"的额外数据,则获取其值并存入变量date中。
    • 如果Intent中包含名为"fragmentID"的额外数据,则获取其值并存入变量currentFragmentID中。否则,保持currentFragmentID的默认值0。
  6. 根据currentFragmentID的值,通过调用不同的私有方法,设置显示不同的Fragment。例如,如果currentFragmentID为0,则显示营养Fragment(Fragment_Nutrition);如果为1,则显示身体统计Fragment(Fragment_BodyStats);如果为2,则显示训练Fragment(Fragment_Workout);如果为3,则显示设置Fragment(Fragment_Settings)。
  7. 设置底部导航栏的点击监听器:查找底部导航栏(BottomNavigationView),并为其设置一个选项选择监听器(setOnItemSelectedListener)。当用户点击导航栏的不同选项时,通过切换Fragment的方式切换显示内容。例如,点击"首页"时,如果当前显示的不是营养Fragment,则切换到营养Fragment,并将currentFragmentID设置为0。
@Override
protected void onDestroy() {
    databaseHelper.close();
    super.onDestroy();
}

这是Activity的onDestroy()方法,当Activity被销毁时调用。在这里,关闭数据库连接,释放资源。


Fragment_Nutrition.java
package com.falyrion.gymtonicapp.fragments;

import android.animation.ObjectAnimator;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;
import android.widget.ImageButton;
import android.widget.ProgressBar;
import android.widget.TableLayout;
import android.widget.TextView;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.falyrion.gymtonicapp.Activity_Main;
import com.falyrion.gymtonicapp.R;
import com.falyrion.gymtonicapp.activities.Activity_Calendar;
import com.falyrion.gymtonicapp.activities.Activity_Meals_AddDailyEntry;
import com.falyrion.gymtonicapp.activities.Activity_Meals_MealsOfDay;

import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;


public class Fragment_Nutrition extends Fragment {

    // TODO: - Add more nutrition details (spurenelemente, metalle, vitamine, etc)
    // - in Add_Meal_Actitvity funktion hinzufügen das man auf ein preset clicken kann und es bearbeiten und löschen
    // - Noch mal schauen ob datum zwischen add_meal_activity und createmealactitvity richtig hin und her gegeben wird
    // - Funktion zum löschen von bereits zum tag hinzugefügten meals
    // - Progress bars schöner machen


    private String date;
    private double[] dataFood;
    private double[] dataGoals;

    private int percentOf(double current, double max) {
        return (int) ((current / max) * 100);
    }

    private String convertDataToDoubleText(double value) {
        // Convert given double to string.
        if (value % 1 == 0) {
            // -> Value has only .0 decimals. Cut it out by converting to int.
            return String.valueOf((int) value);
        } else {
            // -> Value has decimals. Round up to 2 decimal-digits.
            DecimalFormat df = new DecimalFormat("#####.##");
            return String.valueOf(df.format(value));
        }
    }

    private String convertDataToIntText(double value) {
        return String.valueOf((int) value);
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Get date from arguments
        if (getArguments().containsKey("date")) {
            date = getArguments().getString("date");
        } else {
            SimpleDateFormat formatter = new SimpleDateFormat("dd-MM-yyyy", Locale.ENGLISH);
            date = formatter.format(new Date());
        }

        // Load data from database
        Cursor cursorDataFood = ((Activity_Main) requireContext()).databaseHelper.getConsumedMealsSums(date);
        if (cursorDataFood.getCount() > 0) {
            cursorDataFood.moveToFirst();
            dataFood = new double[31];
            for (int i = 0; i <= 30; i++) {
                dataFood[i] = cursorDataFood.getDouble(i);
            }

        } else {
            dataFood = new double[] {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        }
        cursorDataFood.close();

        Cursor cursorSettings = ((Activity_Main) requireContext()).databaseHelper.getSettingsGoals();
        if (cursorSettings.getCount() > 0) {
            cursorSettings.moveToFirst();
            dataGoals = new double[] {
                    cursorSettings.getDouble(0),  // Goal Calories
                    cursorSettings.getDouble(1),  // Goal Fat
                    cursorSettings.getDouble(2),  // Goal Carbohydrates
                    cursorSettings.getDouble(3)  // Goal Protein
            };
        } else {
            dataGoals = new double[] {2000, 2000, 2000, 2000};
        }
        cursorSettings.close();

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_nutrition, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // Date
        TextView textDate = view.findViewById(R.id.textViewDBNDate);
        textDate.setText(date);

        // Set values for main-dashboard
        ProgressBar progressBarMain = getView().findViewById(R.id.progressBarDBNCaloriesMain);
        TextView textProgressMain = getView().findViewById(R.id.textViewDNCaloriesMain);
        ObjectAnimator.ofInt(progressBarMain, "progress", percentOf(dataFood[0], dataGoals[0])).start();
        textProgressMain.setText(convertDataToIntText(dataFood[0]));

        ProgressBar progressBarFat = getView().findViewById(R.id.progressBarDBNFatMain);
        TextView textProgressFat = getView().findViewById(R.id.textViewProgressDBNFatMain);
        ObjectAnimator.ofInt(progressBarFat, "progress", percentOf(dataFood[1], dataGoals[1])).start();
        String textFat = convertDataToIntText(dataFood[1]) + " g";
        textProgressFat.setText(textFat);

        ProgressBar progressBarCarbohydrates = getView().findViewById(R.id.progressBarDBNCarbsMain);
        TextView textProgressCarbohydrates = getView().findViewById(R.id.textViewProgressCarbohydrates);
        ObjectAnimator.ofInt(progressBarCarbohydrates, "progress", percentOf(dataFood[3], dataGoals[2])).start();
        String textCarbohydrates = convertDataToIntText(dataFood[3]) + " g";
        textProgressCarbohydrates.setText(textCarbohydrates);

        ProgressBar progressBarProtein = getView().findViewById(R.id.progressBarDBNProteinMain);
        TextView textProgressProtein = getView().findViewById(R.id.textViewProgressDBNProteinMain);
        ObjectAnimator.ofInt(progressBarProtein, "progress", percentOf(dataFood[5], dataGoals[3])).start();
        String textProtein = convertDataToIntText(dataFood[5]) + " g";
        textProgressProtein.setText(textProtein);

        // Set values for details-dashboard
        TextView textViewDetailsCal = getView().findViewById(R.id.textViewDBNDetailsCalories);
        textViewDetailsCal.setText(convertDataToDoubleText(dataFood[0]));

        TextView textViewDetailsFat = getView().findViewById(R.id.textViewDBNDetailsFat);
        textViewDetailsFat.setText(convertDataToDoubleText(dataFood[1]));

        TextView textViewDetailsFatSat = getView().findViewById(R.id.textViewDBNDetailsFatSat);
        textViewDetailsFatSat.setText(convertDataToDoubleText(dataFood[2]));

        TextView textViewDetailsCarbs = getView().findViewById(R.id.textViewDBNDetailsCarbs);
        textViewDetailsCarbs.setText(convertDataToDoubleText(dataFood[3]));

        TextView textViewDetailsSugar = getView().findViewById(R.id.textViewDBNDetailsSugar);
        textViewDetailsSugar.setText(convertDataToDoubleText(dataFood[4]));

        TextView textViewDetailsProtein = getView().findViewById(R.id.textViewDBNDetailsProtein);
        textViewDetailsProtein.setText(convertDataToDoubleText(dataFood[5]));

        TextView textViewDetailsSalt = getView().findViewById(R.id.textViewDBNDetailsSalt);
        textViewDetailsSalt.setText(convertDataToDoubleText(dataFood[6]));

        TextView textViewDetailsFiber = getView().findViewById(R.id.textViewDBNDetailsFiber);
        textViewDetailsFiber.setText(convertDataToDoubleText(dataFood[7]));

        TextView textViewDetailsChol = getView().findViewById(R.id.textViewDBNDetailsChol);
        textViewDetailsChol.setText(convertDataToDoubleText(dataFood[8]));

        TextView textViewDetailsCreatine = getView().findViewById(R.id.textViewDBNDetailsCreatine);
        textViewDetailsCreatine.setText(convertDataToDoubleText(dataFood[9]));

        TextView textViewDetailsCa = getView().findViewById(R.id.textViewDBNDetailsCa);
        textViewDetailsCa.setText(convertDataToDoubleText(dataFood[10]));

        TextView textViewDetailsFe = getView().findViewById(R.id.textViewDBNDetailsFe);
        textViewDetailsFe.setText(convertDataToDoubleText(dataFood[11]));

        TextView textViewDetailsKa = getView().findViewById(R.id.textViewDBNDetailsKa);
        textViewDetailsKa.setText(convertDataToDoubleText(dataFood[12]));

        TextView textViewDetailsMg = getView().findViewById(R.id.textViewDBNDetailsMg);
        textViewDetailsMg.setText(convertDataToDoubleText(dataFood[13]));

        TextView textViewDetailMn = getView().findViewById(R.id.textViewDBNDetailsMn);
        textViewDetailMn.setText(convertDataToDoubleText(dataFood[14]));

        TextView textViewDetailsNa = getView().findViewById(R.id.textViewDBNDetailsNa);
        textViewDetailsNa.setText(convertDataToDoubleText(dataFood[15]));

        TextView textViewDetailsP = getView().findViewById(R.id.textViewDBNDetailsP);
        textViewDetailsP.setText(convertDataToDoubleText(dataFood[16]));

        TextView textViewDetailsZn = getView().findViewById(R.id.textViewDBNDetailsZn);
        textViewDetailsZn.setText(convertDataToDoubleText(dataFood[17]));

        TextView textViewDetailsVitA = getView().findViewById(R.id.textViewDBNDetailsVitA);
        textViewDetailsVitA.setText(convertDataToDoubleText(dataFood[18]));

        TextView textViewDetailsVitB1 = getView().findViewById(R.id.textViewDBNDetailsVitB1);
        textViewDetailsVitB1.setText(convertDataToDoubleText(dataFood[19]));

        TextView textViewDetailsVitB2 = getView().findViewById(R.id.textViewDBNDetailsVitB2);
        textViewDetailsVitB2.setText(convertDataToDoubleText(dataFood[20]));

        TextView textViewDetailsVitB3 = getView().findViewById(R.id.textViewDBNDetailsVitB3);
        textViewDetailsVitB3.setText(convertDataToDoubleText(dataFood[21]));

        TextView textViewDetailsVitB5 = getView().findViewById(R.id.textViewDBNDetailsVitB5);
        textViewDetailsVitB5.setText(convertDataToDoubleText(dataFood[22]));

        TextView textViewDetailsVitB6 = getView().findViewById(R.id.textViewDBNDetailsVitB6);
        textViewDetailsVitB6.setText(convertDataToDoubleText(dataFood[23]));

        TextView textViewDetailsVitB7 = getView().findViewById(R.id.textViewDBNDetailsVitB7);
        textViewDetailsVitB7.setText(convertDataToDoubleText(dataFood[24]));

        TextView textViewDetailsVitB11 = getView().findViewById(R.id.textViewDBNDetailsVitB11);
        textViewDetailsVitB11.setText(convertDataToDoubleText(dataFood[25]));

        TextView textViewDetailsVitB12 = getView().findViewById(R.id.textViewDBNDetailsVitB12);
        textViewDetailsVitB12.setText(convertDataToDoubleText(dataFood[26]));

        TextView textViewDetailsVitC = getView().findViewById(R.id.textViewDBNDetailsVitC);
        textViewDetailsVitC.setText(convertDataToDoubleText(dataFood[27]));

        TextView textViewDetailsVitE = getView().findViewById(R.id.textViewDBNDetailsVitE);
        textViewDetailsVitE.setText(convertDataToDoubleText(dataFood[28]));

        TextView textViewDetailsVitK = getView().findViewById(R.id.textViewDBNDetailsVitK);
        textViewDetailsVitK.setText(convertDataToDoubleText(dataFood[29]));

        TextView textViewDetailsVitH = getView().findViewById(R.id.textViewDBNDetailsVitH);
        textViewDetailsVitH.setText(convertDataToDoubleText(dataFood[30]));

        // Set buttons
        Button buttonAddMeal = getView().findViewById(R.id.buttonDashboardNutritionAddMeal);
        buttonAddMeal.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Activity_Meals_AddDailyEntry.class);
                intent.putExtra("date", date);
                intent.putExtra("fragmentID", 0);
                // intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);  // Start activity without animation
                startActivity(intent);
            }
        });

        Button buttonShowEatenMeals = getView().findViewById(R.id.buttonEatenMeals);
        buttonShowEatenMeals.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Activity_Meals_MealsOfDay.class);
                intent.putExtra("date", date);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);  // Start activity without animation
                startActivity(intent);
            }
        });

        ImageButton buttonCalendar = getView().findViewById(R.id.buttonDBNCalendar);
        buttonCalendar.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Activity_Calendar.class);
                intent.putExtra("date", date);
                intent.putExtra("fragmentID", 0);
                intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION);  // Start activity without animation
                startActivity(intent);
            }
        });

        TableLayout tableLayoutDetails = view.findViewById(R.id.tableLayoutDashboardNutritionDetails);

        ImageButton buttonToggleDetails = view.findViewById(R.id.buttonExpandNutritionDetails);
        buttonToggleDetails.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (tableLayoutDetails.getVisibility() == View.GONE) {
                    tableLayoutDetails.setVisibility(View.VISIBLE);
                    buttonToggleDetails.setImageResource(R.drawable.ic_baseline_expand_less_24);
                    return;
                }
                tableLayoutDetails.setVisibility(View.GONE);
                buttonToggleDetails.setImageResource(R.drawable.ic_baseline_expand_more_24);
            }
        });

//        ScrollView mainLayout = view.findViewById(R.id.scrollViewMainLayout);
//        mainLayout.setVisibility(View.VISIBLE);
//
//        FrameLayout loadingLayout = view.findViewById(R.id.loadingLayout);
//        loadingLayout.setVisibility(View.GONE);
    }

}
  1. private String date;
    声明了一个私有成员变量date,用于保存日期信息的字符串。

  2. private double[] dataFood;
    声明了一个私有成员变量dataFood,用于保存食物摄入量的数组,包含31个元素,分别对应不同的营养项。

  3. private double[] dataGoals;
    声明了一个私有成员变量dataGoals,用于保存营养目标值的数组,包含4个元素,分别对应目标卡路里、脂肪、碳水化合物和蛋白质。

  4. private int percentOf(double current, double max) { ... }
    这是一个私有方法,用于计算当前值相对于最大值的百分比,返回整数类型。它接收两个参数:current表示当前值,max表示最大值。通过(current / max) * 100计算百分比并将结果转换为整数返回。

  5. private String convertDataToDoubleText(double value) { ... }
    这是一个私有方法,用于将给定的double类型数值转换成字符串。如果数值只有整数部分(小数部分为0),则返回整数形式;否则,保留两位小数并返回。

  6. private String convertDataToIntText(double value) { ... }
    这是一个私有方法,用于将给定的double类型数值转换成整数形式的字符串。

  7. @Override public void onCreate(Bundle savedInstanceState) { ... }
    在Fragment创建时调用。首先调用父类的onCreate方法,然后从传入的参数中获取日期信息并赋值给date变量。接下来,通过数据库助手类获取当天已消耗的餐食总和和用户设定的营养目标值,并分别存储在dataFooddataGoals数组中。

  8. @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { ... }
    在Fragment创建View时调用。通过加载名为fragment_nutrition的布局文件来创建界面,并返回该View。

  9. @Override public void onViewCreated(View view, @Nullable Bundle savedInstanceState) { ... }
    当Fragment的View创建完成后调用,此时可以对View进行操作。

  10. onViewCreated方法中,将获取到的日期信息设置到界面上的日期文本框(TextView)。

  11. 设置主界面中的营养项进度条(ProgressBar)和文本信息(TextView)。首先通过getView()获取视图对象,然后通过findViewById方法找到对应的控件。通过动画效果(ObjectAnimator.ofInt)实现进度条的填充效果。数据从dataFooddataGoals数组中获取,并经过转换成字符串后显示在界面上。

  12. 设置详细营养信息界面中的各个营养项文本信息(TextView)。同样,数据从dataFood数组中获取,并经过转换成字符串后显示在界面上。

  13. 设置两个按钮的点击事件监听器:

  • buttonAddMeal按钮:点击后跳转到添加当天餐食的界面(Activity_Meals_AddDailyEntry),并传递当前日期和Fragment ID作为参数。
  • buttonShowEatenMeals按钮:点击后跳转到查看当天已吃餐食的界面(Activity_Meals_MealsOfDay),并传递当前日期作为参数。
  1. 设置日历按钮buttonCalendar的点击事件监听器,点击后跳转到日历界面(Activity_Calendar),并传递当前日期和Fragment ID作为参数。

  2. 设置buttonToggleDetails按钮的点击事件监听器,用于切换详细营养信息的显示和隐藏。点击按钮时,通过设置详细营养信息表格(tableLayoutDetails)的可见性来实现显示或隐藏,并更改按钮的图标。


Fragment_Settings.java
package com.falyrion.gymtonicapp.fragments;

import android.database.Cursor;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.falyrion.gymtonicapp.Activity_Main;
import com.falyrion.gymtonicapp.R;


public class Fragment_Settings extends Fragment implements AdapterView.OnItemSelectedListener {

    private double[] dataGoals;
    private String[] languages;
    private String currentLanguage;
    private boolean savePossible = false;
    private boolean firstSelect = true;

    private Button saveButton;

    private class textWatcher implements TextWatcher {
        private int id;
        private textWatcher(int id) {
            this.id = id;
        }

        @Override
        public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            // pass
        }

        @Override
        public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
            // pass
        }

        @Override
        public void afterTextChanged(Editable editable) {
            // Update value
            dataGoals[id] = Double.parseDouble(editable.toString());

            // Update background resource of save button
            enableSaveButton();
        }
    }

    private String convertDataToText(double value) {
        // Convert given double to string.
        // Check if double value has ".0" decimals. If yes cut it out.
        if (value % 1 == 0) {
            return String.valueOf((int) value);
        } else {
            return String.valueOf(value);
        }
    }

    private void enableSaveButton() {
        saveButton.setBackgroundResource(R.drawable.shape_box_round_pop);
        saveButton.setTextColor(getContext().getColor(R.color.text_high));
        saveButton.setVisibility(View.VISIBLE);
        savePossible = true;
    }


    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load data from database
        Cursor cursorGoals = ((Activity_Main) requireContext()).databaseHelper.getSettingsGoals();
        if (cursorGoals.getCount() > 0) {
            cursorGoals.moveToFirst();
            dataGoals = new double[] {
                    cursorGoals.getDouble(0),
                    cursorGoals.getDouble(1),
                    cursorGoals.getDouble(2),
                    cursorGoals.getDouble(3)
            };
        } else {
            dataGoals = new double[] {0, 0, 0, 0};
        }
        cursorGoals.close();

        // Languages
        languages = new String[] {
                getResources().getString(R.string.lang_de),
                getResources().getString(R.string.lang_en)
        };
    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_settings, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // Nutrition goal settings
        EditText editTextCalories = getView().findViewById(R.id.editTextSettingsGoalsCal);
        editTextCalories.setText(convertDataToText(dataGoals[0]));
        editTextCalories.addTextChangedListener(new textWatcher(0));

        EditText editTextFat = getView().findViewById(R.id.editTextSettingsGoalsFat);
        editTextFat.setText(convertDataToText(dataGoals[1]));
        editTextFat.addTextChangedListener(new textWatcher(1));

        EditText editTextCarbs = getView().findViewById(R.id.editTextSettingsGoalsCarbs);
        editTextCarbs.setText(convertDataToText(dataGoals[2]));
        editTextCarbs.addTextChangedListener(new textWatcher(2));

        EditText editTextProtein = getView().findViewById(R.id.editTextSettingsGoalsProtein);
        editTextProtein.setText(convertDataToText(dataGoals[3]));
        editTextProtein.addTextChangedListener(new textWatcher(3));


        // Language settings spinner
        Spinner spinner = getView().findViewById(R.id.spinnerLanguages);
        spinner.setOnItemSelectedListener(this);
        ArrayAdapter adapterCategories = new ArrayAdapter(getContext(), R.layout.spinner_item_purple_middle, languages);
        adapterCategories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinner.setAdapter(adapterCategories);

        // Button
        saveButton = getView().findViewById(R.id.buttonSaveSettings);
        saveButton.setVisibility(View.INVISIBLE);
        saveButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (savePossible) {
                    savePossible = false;
                    saveButton.setBackgroundResource(R.drawable.shape_box_round_middle);
                    saveButton.setTextColor(getContext().getColor(R.color.text_middle));
                    saveButton.setVisibility(View.INVISIBLE);

                    ((Activity_Main) requireContext()).databaseHelper.setSettingsGoals(dataGoals[0], dataGoals[1], dataGoals[2], dataGoals[3]);
                    ((Activity_Main) requireContext()).databaseHelper.setSettingsLanguage(currentLanguage);

                }
            }
        });
    }

    // Methods from imported spinner interface -----------------------------------------------------
    @Override
    public void onItemSelected(AdapterView adapterView, View view, int position, long l) {
        // Guard clause against the automatic item select on creation
        if (firstSelect) {
            firstSelect = false;
            return;
        }

        // Set value
        switch (position) {
            case 0: currentLanguage = "de"; break;
            case 1: currentLanguage = "en"; break;
        }

        // Update button
        enableSaveButton();
    }

    @Override
    public void onNothingSelected(AdapterView adapterView) {
        // Pass
    }
}
  1. 导入相关的Android库:
import android.database.Cursor;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Spinner;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;

import com.falyrion.gymtonicapp.Activity_Main;
import com.falyrion.gymtonicapp.R;
  1. 创建一个名为Fragment_Settings的类,继承自Fragment,并实现了AdapterView.OnItemSelectedListener接口。
public class Fragment_Settings extends Fragment implements AdapterView.OnItemSelectedListener {
    // 类的成员变量和方法在下面
}
  1. 定义了一些成员变量:
private double[] dataGoals;
private String[] languages;
private String currentLanguage;
private boolean savePossible = false;
private boolean firstSelect = true;

private Button saveButton;
  1. 创建一个内部类textWatcher,它实现了TextWatcher接口,用于监听输入框文本的变化。
private class textWatcher implements TextWatcher {
    private int id;

    private textWatcher(int id) {
        this.id = id;
    }

    // 在文本改变前不做处理
    @Override
    public void beforeTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        // pass
    }

    // 在文本改变时不做处理
    @Override
    public void onTextChanged(CharSequence charSequence, int i, int i1, int i2) {
        // pass
    }

    // 在文本改变后,更新对应目标值和保存按钮状态
    @Override
    public void afterTextChanged(Editable editable) {
        dataGoals[id] = Double.parseDouble(editable.toString());
        enableSaveButton();
    }
}
  1. 定义了一些私有方法:
private String convertDataToText(double value) {
    // 将给定的double转换为字符串,并检查是否有".0"的小数部分,有则删除
    if (value % 1 == 0) {
        return String.valueOf((int) value);
    } else {
        return String.valueOf(value);
    }
}

private void enableSaveButton() {
    // 更新保存按钮的背景和可见性,用于表示用户可以保存设置
    saveButton.setBackgroundResource(R.drawable.shape_box_round_pop);
    saveButton.setTextColor(getContext().getColor(R.color.text_high));
    saveButton.setVisibility(View.VISIBLE);
    savePossible = true;
}
  1. onCreate()方法:
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    // 从数据库中加载数据
    Cursor cursorGoals = ((Activity_Main) requireContext()).databaseHelper.getSettingsGoals();
    if (cursorGoals.getCount() > 0) {
        cursorGoals.moveToFirst();
        dataGoals = new double[] {
                cursorGoals.getDouble(0),
                cursorGoals.getDouble(1),
                cursorGoals.getDouble(2),
                cursorGoals.getDouble(3)
        };
    } else {
        dataGoals = new double[] {0, 0, 0, 0};
    }
    cursorGoals.close();

    // 设置语言选项
    languages = new String[] {
            getResources().getString(R.string.lang_de),
            getResources().getString(R.string.lang_en)
    };
}
  1. onCreateView()方法:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
                         Bundle savedInstanceState) {
    // 加载并返回fragment_settings布局
    return inflater.inflate(R.layout.fragment_settings, container, false);
}
  1. onViewCreated()方法:
@Override
public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
    // 获取布局中的输入框,并显示对应的目标值
    EditText editTextCalories = getView().findViewById(R.id.editTextSettingsGoalsCal);
    editTextCalories.setText(convertDataToText(dataGoals[0]));
    editTextCalories.addTextChangedListener(new textWatcher(0));

    EditText editTextFat = getView().findViewById(R.id.editTextSettingsGoalsFat);
    editTextFat.setText(convertDataToText(dataGoals[1]));
    editTextFat.addTextChangedListener(new textWatcher(1));

    EditText editTextCarbs = getView().findViewById(R.id.editTextSettingsGoalsCarbs);
    editTextCarbs.setText(convertDataToText(dataGoals[2]));
    editTextCarbs.addTextChangedListener(new textWatcher(2));

    EditText editTextProtein = getView().findViewById(R.id.editTextSettingsGoalsProtein);
    editTextProtein.setText(convertDataToText(dataGoals[3]));
    editTextProtein.addTextChangedListener(new textWatcher(3));


    // 设置语言选项的Spinner
    Spinner spinner = getView().findViewById(R.id.spinnerLanguages);
    spinner.setOnItemSelectedListener(this);
    ArrayAdapter adapterCategories = new ArrayAdapter(getContext(), R.layout.spinner_item_purple_middle, languages);
    adapterCategories.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
    spinner.setAdapter(adapterCategories);

    // 设置保存按钮
    saveButton = getView().findViewById(R.id.buttonSaveSettings);
    saveButton.setVisibility(View.INVISIBLE);
    saveButton.setOnClickListener(new View.OnClickListener() {
        @Override
        public void onClick(View view) {
            // 如果保存按钮可用,则保存数据到数据库,并隐藏保存按钮
            if (savePossible) {
                savePossible = false;
                saveButton.setBackgroundResource(R.drawable.shape_box_round_middle);
                saveButton.setTextColor(getContext().getColor(R.color.text_middle));
                saveButton.setVisibility(View.INVISIBLE);

                ((Activity_Main) requireContext()).databaseHelper.setSettingsGoals(dataGoals[0], dataGoals[1], dataGoals[2], dataGoals[3]);
                ((Activity_Main) requireContext()).databaseHelper.setSettingsLanguage(currentLanguage);
            }
        }
    });
}
  1. 方法从导入的AdapterView.OnItemSelectedListener接口中继承:
@Override
public void onItemSelected(AdapterView<?> adapterView, View view, int position, long l) {
    // 防止在创建时自动选择项
    if (firstSelect) {
        firstSelect = false;
        return;
    }

    // 设置语言选项,并更新保存按钮状态
    switch (position) {
        case 0: currentLanguage = "de"; break;
        case 1: currentLanguage = "en"; break;
    }
    enableSaveButton();
}

@Override
public void onNothingSelected(AdapterView<?> adapterView) {
    // 无操作
}

总体来说,这段代码是一个用于设置健身目标和语言选项的Fragment,它在用户修改了目标值或语言选项时,会显示一个保存按钮,允许用户保存设置到数据库。注意其中涉及了数据库操作和布局文件的相关处理。


package com.falyrion.gymtonicapp.fragments;

import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.falyrion.gymtonicapp.Activity_Main;
import com.falyrion.gymtonicapp.R;
import com.falyrion.gymtonicapp.activities.Activity_Workout_CreateEditExercise;
import com.falyrion.gymtonicapp.activities.Activity_Workout_EditPlans;
import com.falyrion.gymtonicapp.activities.Activity_Workout_EditRoutines;
import com.falyrion.gymtonicapp.recyclerview.Adapter_Workout_Exercise;
import com.falyrion.gymtonicapp.recyclerview.Adapter_Workout_Routine;
import com.falyrion.gymtonicapp.recyclerview.Item_Workout_Exercise;
import com.falyrion.gymtonicapp.recyclerview.Item_Workout_Routine;
import com.google.android.material.floatingactionbutton.FloatingActionButton;
import com.google.android.material.snackbar.Snackbar;

import java.util.ArrayList;


public class Fragment_Workout extends Fragment implements Adapter_Workout_Routine.Interface_Workout_Routine, Adapter_Workout_Exercise.Interface_Workout_Exercises, AdapterView.OnItemSelectedListener {

    private String[] workoutPlans;
    private ArrayList workoutRoutines;
    private ArrayList workoutExercises;
    private int selectedPlanIdx = -1;
    private int selectedRoutineIdx = -1;
    private RecyclerView recyclerViewRoutines;
    private RecyclerView recyclerViewExercises;
    private Adapter_Workout_Routine adapterRoutines;
    private Adapter_Workout_Exercise adapterExercises;

    private boolean fabOpen = false;
    private FloatingActionButton fabMain;
    private LinearLayout linearLayoutFABSub01;
    private LinearLayout linearLayoutFABSub02;
    private LinearLayout linearLayoutFABSub03;
    private View backgroundBlur;

    TextView sectionTitleRoutines;
    TextView sectionTitleExercises;


    private String[] loadPlansFromDatabase() {
        Cursor cursor = ((Activity_Main) requireContext()).databaseHelper.getWorkoutPlans();
        String[] loadedPlans = new String[0];

        if (cursor.getCount() > 0) {
            // Initiate array with length of cursor data
            loadedPlans = new String[cursor.getCount()];
            // Add plan-names to array
            int j = 0;
            while (cursor.moveToNext()) {
                loadedPlans[j] = cursor.getString(0);
                j++;
            }
        }
        cursor.close();

        return loadedPlans;
    }

    private ArrayList loadRoutinesFromDatabase(String workoutPlan) {
        Cursor cursor = ((Activity_Main) requireContext()).databaseHelper.getWorkoutRoutines(workoutPlan);
        ArrayList loadedRoutines = new ArrayList();

        if (cursor.getCount() > 0) {
            cursor.moveToFirst();
            loadedRoutines.add(cursor.getPosition(), new Item_Workout_Routine(cursor.getString(0), true));

            while (cursor.moveToNext()) {
                loadedRoutines.add(cursor.getPosition(), new Item_Workout_Routine(cursor.getString(0), false));
            }
        }

        return loadedRoutines;
    }

    private ArrayList loadExercisesFromDatabase(String workoutPlan, String workoutRoutine) {
        Cursor cursor = ((Activity_Main) requireContext()).databaseHelper.getWorkoutExercises(workoutPlan, workoutRoutine);
        ArrayList loadedExercises = new ArrayList();

        if (cursor.getCount() > 0) {
            while (cursor.moveToNext()) {
                loadedExercises.add(
                        cursor.getPosition(),
                        new Item_Workout_Exercise(
                                cursor.getString(0),  // Title
                                cursor.getInt(1),  // Sets
                                cursor.getInt(2),  // Reps
                                cursor.getDouble(3)  // Weight
                        )
                );
            }
        }

        return loadedExercises;
    }

    private void toggleFABMenu() {
        if (fabOpen) {
            // Close FAB-menu
            fabOpen = false;
            fabMain.setImageResource(R.drawable.ic_baseline_add_circle_24);
            linearLayoutFABSub01.setTranslationY(0);
            linearLayoutFABSub02.setTranslationY(0);
            linearLayoutFABSub03.setTranslationY(0);
            linearLayoutFABSub01.setVisibility(View.INVISIBLE);
            linearLayoutFABSub02.setVisibility(View.INVISIBLE);
            linearLayoutFABSub03.setVisibility(View.INVISIBLE);
            backgroundBlur.setVisibility(View.GONE);
        } else {
            // Oben FAB-menu
            fabOpen = true;
            backgroundBlur.setVisibility(View.VISIBLE);
            fabMain.setImageResource(R.drawable.ic_baseline_remove_circle_24);
            linearLayoutFABSub01.setVisibility(View.VISIBLE);
            linearLayoutFABSub02.setVisibility(View.VISIBLE);
            linearLayoutFABSub03.setVisibility(View.VISIBLE);
            linearLayoutFABSub01.animate().translationY(-170);
            linearLayoutFABSub02.animate().translationY(-340);
            linearLayoutFABSub03.animate().translationY(-510);
        }
    }


    // Override class default methods --------------------------------------------------------------

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // Load data from database and fill lists and create adapters

        workoutPlans = loadPlansFromDatabase();
        selectedPlanIdx = 0;

        workoutRoutines = loadRoutinesFromDatabase(workoutPlans[0]);

        if (!workoutRoutines.isEmpty()) {
            workoutExercises = loadExercisesFromDatabase(workoutPlans[0], workoutRoutines.get(0).getTitle());
            Log.d("uwu", "routines size: " + workoutRoutines.size());
            Log.d("uwu", "exerzises size: " + workoutExercises.size());
        }

    }

    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        return inflater.inflate(R.layout.fragment_workout, container, false);
    }

    @Override
    public void onViewCreated(View view, @Nullable Bundle savedInstanceState) {
        // Set up recycler-views

        sectionTitleRoutines = view.findViewById(R.id.sectionTitleRoutines);
        sectionTitleExercises = view.findViewById(R.id.sectionTitleExercises);

        Spinner spinnerPlans = view.findViewById(R.id.spinnerWorkoutPlans);
        spinnerPlans.setOnItemSelectedListener(this);
        ArrayAdapter adapterPlans = new ArrayAdapter(getContext(), R.layout.spinner_item_purple_middle, workoutPlans);
        adapterPlans.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
        spinnerPlans.setAdapter(adapterPlans);

        recyclerViewRoutines = view.findViewById(R.id.recyclerViewRoutines);
        if (!workoutRoutines.isEmpty()) {
            adapterRoutines = new Adapter_Workout_Routine(workoutRoutines, this);
            recyclerViewRoutines.setAdapter(adapterRoutines);
            recyclerViewRoutines.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
            selectedRoutineIdx = 0;
        } else {
            sectionTitleRoutines.setVisibility(View.INVISIBLE);
        }

        recyclerViewExercises = view.findViewById(R.id.recyclerViewExercises);
        if (!workoutExercises.isEmpty()) {
            adapterExercises = new Adapter_Workout_Exercise(workoutExercises, this);
            recyclerViewExercises.setAdapter(adapterExercises);
            recyclerViewExercises.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
        } else {
            sectionTitleExercises.setVisibility(View.INVISIBLE);
        }

        // FAB-Views -------------------------------------------------------------------------------

        linearLayoutFABSub01 = view.findViewById(R.id.linearLayoutFAB01);
        linearLayoutFABSub02 = view.findViewById(R.id.linearLayoutFAB02);
        linearLayoutFABSub03 = view.findViewById(R.id.linearLayoutFAB03);
        backgroundBlur = view.findViewById(R.id.fragmentExercisesBlur);
        fabMain = view.findViewById(R.id.fabExercisesMain);
        FloatingActionButton fabSub01 = view.findViewById(R.id.fabExercises01);
        FloatingActionButton fabSub02 = view.findViewById(R.id.fabExercises02);
        FloatingActionButton fabSub03 = view.findViewById(R.id.fabExercises03);

        // Main Button
        fabMain.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggleFABMenu();
            }
        });

        // Background blur
        backgroundBlur.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                toggleFABMenu();
            }
        });

        // Button "Add Exercise"
        fabSub01.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                if (workoutRoutines.isEmpty()) {
                    Snackbar.make(view, "Please create at least one workout routine first!", Snackbar.LENGTH_SHORT).show();
                    return;
                }

                Intent intent = new Intent(view.getContext(), Activity_Workout_CreateEditExercise.class);
                intent.putExtra("date", ((Activity_Main) requireContext()).date);
                startActivity(intent);
            }
        });

        // Button "Add Routine"
        fabSub02.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                // Check if at least 1 plan exists, else do not open new activity
                if (workoutPlans.length <= 0) {
                    Toast.makeText(getContext(), "You must create at least 1 workout plan first!", Toast.LENGTH_SHORT).show();
                    return;
                }

                // Start activity
                Intent intent = new Intent(view.getContext(), Activity_Workout_EditRoutines.class);
                startActivity(intent);
            }
        });

        // Button "Add Plan"
        fabSub03.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                Intent intent = new Intent(view.getContext(), Activity_Workout_EditPlans.class);
                startActivity(intent);
            }
        });

    }


    // Interface methods ---------------------------------------------------------------------------

    // Spinner Plan Methods
    @Override
    public void onItemSelected(AdapterView adapterView, View view, int position, long l) {
        if (position == selectedPlanIdx) {
            return;
        }

        selectedPlanIdx = position;

        // Update routines
        workoutRoutines.clear();
        if (adapterRoutines != null) {
            adapterRoutines.notifyDataSetChanged();
        }

        workoutExercises.clear();
        if (adapterExercises != null) {
            adapterExercises.notifyDataSetChanged();
        }

        workoutRoutines = loadRoutinesFromDatabase(workoutPlans[selectedPlanIdx]);

        if (workoutRoutines.isEmpty()) {
            sectionTitleRoutines.setVisibility(View.INVISIBLE);
            sectionTitleExercises.setVisibility(View.INVISIBLE);
            return;
        }

        adapterRoutines = new Adapter_Workout_Routine(workoutRoutines, this);
        recyclerViewRoutines.setAdapter(adapterRoutines);
        recyclerViewRoutines.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.HORIZONTAL, false));
        selectedRoutineIdx = 0;
        sectionTitleRoutines.setVisibility(View.VISIBLE);

        // Updates exercises
        workoutExercises = loadExercisesFromDatabase(workoutPlans[selectedPlanIdx], workoutRoutines.get(selectedRoutineIdx).getTitle());

        if (!workoutExercises.isEmpty()) {
            adapterExercises = new Adapter_Workout_Exercise(workoutExercises, this);
            recyclerViewExercises.setAdapter(adapterExercises);
            recyclerViewExercises.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
            sectionTitleExercises.setVisibility(View.VISIBLE);
        }
    }

    @Override
    public void onNothingSelected(AdapterView adapterView) {
        // Pass
    }

    // Routine adapter methods
    @Override
    public void onRoutineItemClick(int itemPosition) {
        if (selectedRoutineIdx == -1) {
            return;
        }

        if (itemPosition == selectedRoutineIdx) {
            return;
        }

        // Update routine-items visually
        workoutRoutines.get(itemPosition).setIsSelected(true);
        workoutRoutines.get(selectedRoutineIdx).setIsSelected(false);
        adapterRoutines.notifyItemChanged(itemPosition);
        adapterRoutines.notifyItemChanged(selectedRoutineIdx);

        selectedRoutineIdx = itemPosition;

        // Update exercises
        workoutExercises.clear();
        if (adapterExercises != null) {
            adapterExercises.notifyDataSetChanged();
        }


        workoutExercises = loadExercisesFromDatabase(workoutPlans[selectedPlanIdx], workoutRoutines.get(selectedRoutineIdx).getTitle());

        if (!workoutExercises.isEmpty()) {
            adapterExercises = new Adapter_Workout_Exercise(workoutExercises, this);
            recyclerViewExercises.setAdapter(adapterExercises);
            recyclerViewExercises.setLayoutManager(new LinearLayoutManager(getContext(), LinearLayoutManager.VERTICAL, false));
        }


        // adapterExercises.notifyDataSetChanged();
    }

    // Exercise adapter methods
    @Override
    public void onExerciseItemClick(int itemPosition) {
        Intent intent = new Intent(getContext(), Activity_Workout_CreateEditExercise.class);
        intent.putExtra("date", ((Activity_Main) requireContext()).date);
        intent.putExtra("mode", "edit");
        intent.putExtra("planName", workoutPlans[selectedPlanIdx]);
        intent.putExtra("routineName", workoutRoutines.get(selectedRoutineIdx).getTitle());
        intent.putExtra("exerciseName", workoutExercises.get(itemPosition).getTitle());
        intent.putExtra("exerciseSets", workoutExercises.get(itemPosition).getSets());
        intent.putExtra("exerciseReps", workoutExercises.get(itemPosition).getRepetitions());
        intent.putExtra("exerciseWeight", workoutExercises.get(itemPosition).getWeight());
        startActivity(intent);
    }

}
  1. 导入所需的Android类和自定义类:
    代码中首先导入了一些必要的Android类和自定义的类,这些类包括数据库操作、RecyclerView适配器和其他视图组件。

  2. 定义Fragment类:
    Fragment_Workout类是一个继承自Fragment的Java类,它实现了Adapter_Workout_Routine.Interface_Workout_Routine、Adapter_Workout_Exercise.Interface_Workout_Exercises和AdapterView.OnItemSelectedListener接口。

  3. 声明和初始化一些变量:
    代码中声明了一些成员变量,用于存储用户的训练计划、训练例程和训练细节等信息。这些变量包括:

    • workoutPlans:存储训练计划的字符串数组。
    • workoutRoutines:存储训练例程的自定义类Item_Workout_Routine的ArrayList。
    • workoutExercises:存储训练细节的自定义类Item_Workout_Exercise的ArrayList。
    • selectedPlanIdx:当前选中的训练计划在workoutPlans数组中的索引。
    • selectedRoutineIdx:当前选中的训练例程在workoutRoutines数组中的索引。
  4. 从数据库加载数据:

    • loadPlansFromDatabase()方法:从数据库中获取所有的训练计划,并返回一个存储训练计划名称的字符串数组。
    • loadRoutinesFromDatabase(String workoutPlan)方法:根据传入的训练计划名称从数据库中获取对应的训练例程,并返回一个存储训练例程的Item_Workout_Routine的ArrayList。
    • loadExercisesFromDatabase(String workoutPlan, String workoutRoutine)方法:根据传入的训练计划名称和训练例程名称从数据库中获取对应的训练细节,并返回一个存储训练细节的Item_Workout_Exercise的ArrayList。
  5. toggleFABMenu()方法:
    这是一个用于控制浮动操作按钮(FloatingActionButton)动画和显示的方法。根据fabOpen变量的值,切换浮动操作按钮的显示状态,从而呈现打开或关闭的动画效果。

  6. 重写Fragment的默认方法:

    • onCreate()方法:在Fragment创建时调用,用于加载数据和初始化变量。
    • onCreateView()方法:在Fragment创建视图时调用,用于加载布局文件。
    • onViewCreated()方法:在视图创建后调用,用于设置RecyclerView、Spinner和浮动操作按钮等的事件监听和适配器。
  7. 实现接口方法:

    • onItemSelected(AdapterView adapterView, View view, int position, long l)方法:当Spinner中的选项被选中时调用,根据选择的训练计划,更新展示的训练例程和训练细节列表。
    • onNothingSelected(AdapterView adapterView)方法:当Spinner中没有选项被选中时调用,这里没有实现任何操作。
    • onRoutineItemClick(int itemPosition)方法:当点击训练例程列表中的某一项时调用,用于更新选中的训练例程,并刷新训练细节列表。
    • onExerciseItemClick(int itemPosition)方法:当点击训练细节列表中的某一项时调用,用于编辑选中的训练细节,打开一个新的Activity页面。

这段代码的主要功能是实现一个展示用户训练计划和训练细节的页面,并且支持添加新的训练计划、训练例程和训练细节。用户可以通过界面上的Spinner选择不同的训练计划,然后展示该计划下的训练例程和训练细节列表。用户还可以通过浮动操作按钮执行添加训练例程、训练细节和训练计划的操作。

三.项目源码

链接:https://pan.baidu.com/s/1F3fEFvEiiGqL1kNZLN_EHA?pwd=jynl
提取码:jynl

创作不易,项目已加密,有偿(仅一杯奶茶钱,可做实验报告,代码讲解等)

请私信作者或

(v)15135757306

你可能感兴趣的:(Android开源项目,android,性能优化,服务器)