¿Cómo crear una aplicación de Android simple para ejercicios de respiración?

Los móviles Android son muy útiles y proporcionan la información de forma instantánea. Solo suponga que está continuamente volando o atendiendo pacientes o participando en reuniones, etc., con mucha frecuencia. Durante esos momentos, hay posibilidades de estresarse y, por lo tanto, la meditación es muy esencial en esta vida acelerada. Aquí proporcionamos el código fuente para la aplicación de ejercicios de respiración y seguramente eso será útil para tener más energía y entusiasmo. A continuación se proporciona un GIF de muestra para tener una idea de lo que vamos a hacer en este artículo. Tenga en cuenta que vamos a implementar este proyecto utilizando el  lenguaje Java  . 

Build a Simple Android App for Breathing Exercise Sample GIF

Implementación paso a paso

Paso 1: Crear un nuevo proyecto

Para crear un nuevo proyecto en Android Studio, consulte Cómo crear/iniciar un nuevo proyecto en Android Studio . Tenga en cuenta que seleccione Java como lenguaje de programación.

Paso 2: antes de ir a la sección de codificación, primero debe hacer una tarea previa

Vaya a la aplicación > res > valores > archivo colors.xml y configure los colores para su aplicación.

XML

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <color name="colorPrimaryLight">#5db839</color>
    <color name="colorPrimary">#0F9D58</color>
    <color name="colorPrimaryDark">#0F9D58</color>
    <color name="colorAccent">#FF4081</color>
</resources>

Vaya al archivo Gradle Scripts > build.gradle (Módulo: aplicación) e importe las siguientes dependencias y haga clic en » Sincronizar ahora » en la ventana emergente anterior.

compile fileTree (dir: ‘libs’, incluya: [‘*.jar’])

   androidTestCompile(‘com.android.support.test.espresso:espresso-core:2.2.2’, {

       excluir grupo: ‘com.android.support’, módulo: ‘apoyo-anotaciones’

   })

A continuación se muestra el código completo para el archivo build.gradle (Módulo: aplicación) :

Java

apply plugin: 'com.android.application'
  
android {
    compileSdkVersion 27
    buildToolsVersion "27.0.3"
    defaultConfig {
        applicationId "com.example.breath"
        minSdkVersion 21
        targetSdkVersion 27
        versionCode 1
        versionName "1.0"
        testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
        vectorDrawables.useSupportLibrary = true
    }
    buildTypes {
        release {
            minifyEnabled false
            proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
        }
    }
}
  
dependencies {
    compile fileTree(dir: 'libs', include: ['*.jar'])
    androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', {
        exclude group: 'com.android.support', module: 'support-annotations'
    })
    compile 'com.android.support:appcompat-v7:27.1.0'
    compile 'com.android.support:design:27.1.0'
    compile 'com.android.support.constraint:constraint-layout:1.0.2'
    testCompile 'junit:junit:4.12'
}

Paso 3: diseñar la parte de la interfaz de usuario

Trabajando con el archivo activity_main.xml:

Vaya al archivo activity_main.xml y consulte el siguiente código. A continuación se muestra el código para el archivo activity_main.xml .

XML

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:fitsSystemWindows="true"
    android:orientation="vertical">
  
    <include layout="@layout/content_main" />
  
</LinearLayout>

Aquí se incluyó content_main.xml . A continuación se muestra el código para ello:

XML

<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/lt_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layout_behavior="@string/appbar_scrolling_view_behavior"
    tools:context="com.example.breath.view.MainActivity">
  
    <View
        android:id="@+id/view_circle_outer"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:layout_marginLeft="@dimen/activity_horizontal_margin"
        android:layout_marginRight="@dimen/activity_horizontal_margin"
        android:background="@drawable/bg_circle_outer"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintDimensionRatio="1:1"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent" />
  
    <View
        android:id="@+id/view_circle_inner"
        android:layout_width="150dp"
        android:layout_height="150dp"
        android:background="@drawable/bg_circle_inner"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintVertical_bias="0.501" />
  
    <TextView
        android:id="@+id/txt_status"
        android:layout_width="50dp"
        android:layout_height="wrap_content"
        android:gravity="center"
        android:text="HOLD"
        android:textColor="#4dd1b2"
        android:textSize="@dimen/hold_text_size"
        app:layout_constraintBottom_toBottomOf="@+id/view_circle_inner"
        app:layout_constraintLeft_toLeftOf="@+id/view_circle_inner"
        app:layout_constraintRight_toRightOf="@+id/view_circle_inner"
        app:layout_constraintTop_toTopOf="@+id/view_circle_inner" />
  
</android.support.constraint.ConstraintLayout>

Puede ver en el código anterior como «bg_circle_inner » y » bg_circle_outer «. Que necesitamos crear (Ir al dibujable > clic derecho > Nuevo > Archivo de recursos dibujable ) en la carpeta dibujable.

A continuación se muestra el código para el archivo bg_circle_inner.xml :

XML

<?xml version="1.0" encoding="utf-8"?>
<shape
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
    <solid android:color="@android:color/white" />
</shape>

A continuación se muestra el código para el archivo bg_circle_outer.xml :

XML

<?xml version="1.0" encoding="utf-8"?>
<shape 
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:shape="oval">
  
    <gradient
        android:angle="90"
        android:endColor="@color/colorPrimaryDark"
        android:startColor="@color/colorPrimaryLight" />
  
</shape>

Básicamente, bg_circle_outer.xml y bg_circle_inner.xml son los archivos XML que crean una forma ovalada y se usan en content_main.xml . Querían mostrar el propósito de » inhalar » y » exhalar «.

Paso 4: trabajar con el archivo Java

Trabajando con el archivo MainActivity.java:

Vaya al archivo MainActivity.java y consulte el siguiente código. A continuación se muestra el código del archivo MainActivity.java

Java

import android.os.Bundle;
import android.os.Handler;
import android.support.constraint.ConstraintLayout;
import android.support.design.widget.FloatingActionButton;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import android.view.View;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.TextView;
  
import com.example.breath.R;
import com.example.breath.utils.Constants;
import com.example.breath.utils.SettingsUtils;
  
public class MainActivity extends AppCompatActivity implements SettingsDialog.SettingsChangeListener {
  
    private static final String TAG = MainActivity.class.getSimpleName();
  
    private ConstraintLayout contentLayout;
    private TextView statusText;
    private View outerCircleView, innerCircleView;
    private FloatingActionButton fab;
  
    private Animation animationInhaleText, animationExhaleText, animationInhaleInnerCircle, animationExhaleInnerCircle;
    private Handler handler = new Handler();
  
    private int holdDuration = 0;
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
  
        contentLayout = findViewById(R.id.lt_content);
  
        statusText = findViewById(R.id.txt_status);
        statusText.setText(Constants.INHALE);
  
        outerCircleView = findViewById(R.id.view_circle_outer);
        innerCircleView = findViewById(R.id.view_circle_inner);
  
        setupBackgroundColor();
  
        prepareAnimations();
        statusText.startAnimation(animationInhaleText);
        innerCircleView.startAnimation(animationInhaleInnerCircle);
    }
  
    private void setupBackgroundColor() {
        int backgroundResId = SettingsUtils.getBackgroundByPresetPosition(SettingsUtils.getSelectedPreset());
        setOuterCircleBackground(R.color.colorPrimaryDark);
    }
  
    private void setOuterCircleBackground(int backgroundResId) {
        outerCircleView.setBackgroundResource(backgroundResId);
    }
  
    private void setInhaleDuration(int duration) {
        animationInhaleText.setDuration(duration);
        animationInhaleInnerCircle.setDuration(duration);
    }
  
    private void setExhaleDuration(int duration) {
        animationExhaleText.setDuration(duration);
        animationExhaleInnerCircle.setDuration(duration);
    }
  
    private void prepareAnimations() {
        int inhaleDuration = SettingsUtils.getSelectedInhaleDuration();
        int exhaleDuration = SettingsUtils.getSelectedExhaleDuration();
        holdDuration = SettingsUtils.getSelectedHoldDuration();
  
        // Inhale - make large
        animationInhaleText = AnimationUtils.loadAnimation(this, R.anim.anim_text_inhale);
        animationInhaleText.setFillAfter(true);
        animationInhaleText.setAnimationListener(inhaleAnimationListener);
  
        animationInhaleInnerCircle = AnimationUtils.loadAnimation(this, R.anim.anim_inner_circle_inhale);
        animationInhaleInnerCircle.setFillAfter(true);
        animationInhaleInnerCircle.setAnimationListener(inhaleAnimationListener);
  
        setInhaleDuration(inhaleDuration);
  
        // Exhale - make small
        animationExhaleText = AnimationUtils.loadAnimation(this, R.anim.anim_text_exhale);
        animationExhaleText.setFillAfter(true);
        animationExhaleText.setAnimationListener(exhaleAnimationListener);
  
        animationExhaleInnerCircle = AnimationUtils.loadAnimation(this, R.anim.anim_inner_circle_exhale);
        animationExhaleInnerCircle.setFillAfter(true);
        animationExhaleInnerCircle.setAnimationListener(exhaleAnimationListener);
  
        setExhaleDuration(exhaleDuration);
  
    }
  
    private Animation.AnimationListener inhaleAnimationListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
  
        }
  
        @Override
        public void onAnimationEnd(Animation animation) {
            Log.d(TAG, "inhale animation end");
            statusText.setText(Constants.HOLD);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    statusText.setText(Constants.EXHALE);
                    statusText.startAnimation(animationExhaleText);
                    innerCircleView.startAnimation(animationExhaleInnerCircle);
                }
            }, holdDuration);
        }
  
        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };
  
    private Animation.AnimationListener exhaleAnimationListener = new Animation.AnimationListener() {
        @Override
        public void onAnimationStart(Animation animation) {
        }
  
        @Override
        public void onAnimationEnd(Animation animation) {
            Log.d(TAG, "exhale animation end");
            statusText.setText(Constants.HOLD);
            handler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    statusText.setText(Constants.INHALE);
                    statusText.startAnimation(animationInhaleText);
                    innerCircleView.startAnimation(animationInhaleInnerCircle);
                }
            }, holdDuration);
        }
  
        @Override
        public void onAnimationRepeat(Animation animation) {
        }
    };
  
    @Override
    public void onPresetChanged(int backgroundResId) {
        setOuterCircleBackground(backgroundResId);
    }
  
    @Override
    public void onInhaleValueChanged(int duration) {
        setInhaleDuration(duration);
    }
  
    @Override
    public void onExhaleValueChanged(int duration) {
        setExhaleDuration(duration);
    }
  
    @Override
    public void onHoldValueChanged(int duration) {
        holdDuration = duration;
    }
}

Cree una nueva clase Java y nombre el archivo como SettingsUtils. A continuación se muestra el código para el archivo de clase  SettingsUtils.java .

Java

public class SettingsUtils {
  
    public static int getBackgroundByPresetPosition(int position) {
        Preset preset = Preset.values()[position];
        return preset.getResId();
    }
  
    public static void saveSelectedPreset(int presetIndex) {
        BreathePreferences.getInstance().putInt(BreathePreferences.SELECTED_PRESET_KEY, presetIndex);
    }
  
    public static int getSelectedPreset() {
        int preset = BreathePreferences.getInstance().getInt(BreathePreferences.SELECTED_PRESET_KEY);
        return preset != -1 ? preset : Constants.DEFAULT_PRESET_INDEX;
    }
  
    public static void saveSelectedInhaleDuration(int duration) {
        BreathePreferences.getInstance().putInt(BreathePreferences.SELECTED_INHALE_DURATION_KEY, duration);
    }
  
    public static int getSelectedInhaleDuration() {
        int duration = BreathePreferences.getInstance().getInt(BreathePreferences.SELECTED_INHALE_DURATION_KEY);
        return duration != -1 ? duration : Constants.DEFAULT_DURATION;
    }
  
    public static void saveSelectedExhaleDuration(int duration) {
        BreathePreferences.getInstance().putInt(BreathePreferences.SELECTED_EXHALE_DURATION_KEY, duration);
    }
  
    public static int getSelectedExhaleDuration() {
        int duration = BreathePreferences.getInstance().getInt(BreathePreferences.SELECTED_EXHALE_DURATION_KEY);
        return duration != -1 ? duration : Constants.DEFAULT_DURATION;
    }
  
    public static void saveSelectedHoldDuration(int duration) {
        BreathePreferences.getInstance().putInt(BreathePreferences.SELECTED_HOLD_DURATION_KEY, duration);
    }
  
    public static int getSelectedHoldDuration() {
        int duration = BreathePreferences.getInstance().getInt(BreathePreferences.SELECTED_HOLD_DURATION_KEY);
        return duration != -1 ? duration : Constants.DEFAULT_DURATION;
    }
}

Cree una nueva clase Java y nombre el archivo como BreathePreferences. A continuación se muestra el código para el archivo de clase  BreathePreferences.java .

Java

import android.content.Context;
import android.content.SharedPreferences;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
  
public class BreathePreferences {
  
    static final String SELECTED_PRESET_KEY = "selectedPreset";
    static final String SELECTED_INHALE_DURATION_KEY = "selectedInhaleDuration";
    static final String SELECTED_EXHALE_DURATION_KEY = "selectedExhaleDuration";
    static final String SELECTED_HOLD_DURATION_KEY = "selectedHoldDuration";
  
    private static final String BREATHE_PREFS = "BreathePreferences";
  
    private static BreathePreferences instance;
  
    private SharedPreferences prefs;
  
    private BreathePreferences(@NonNull Context context) {
        prefs = context.getSharedPreferences(BREATHE_PREFS, Context.MODE_PRIVATE);
    }
  
    public static void init(@NonNull Context context) {
        if (instance == null) {
            instance = new BreathePreferences(context);
        }
    }
  
    public static BreathePreferences getInstance() {
        if (instance == null) {
            Log.e(BreathePreferences.class.getSimpleName(), "Call init() first");
        }
  
        return instance;
    }
  
    public void putString(@NonNull String key, @NonNull String value) {
        prefs.edit().putString(key, value).apply();
    }
  
    public void putLong(@NonNull String key, long value) {
        prefs.edit().putLong(key, value).apply();
    }
  
    public void putInt(@NonNull String key, int value) {
        prefs.edit().putInt(key, value).apply();
    }
  
    public void putFloat(@NonNull String key, float value) {
        prefs.edit().putFloat(key, value).apply();
    }
  
    @Nullable
    public String getString(@NonNull String key) {
        return prefs.getString(key, null);
    }
  
    public long getLong(@NonNull String key) {
        return prefs.getLong(key, -1);
    }
  
    public int getInt(@NonNull String key) {
        return prefs.getInt(key, -1);
    }
  
    public float getFloat(@NonNull String key) {
        return prefs.getFloat(key, -1);
    }
  
    public void clearAll() {
        prefs.edit().clear().apply();
    }
}

Cree una nueva clase Java y nombre el archivo como Constantes. A continuación se muestra el código para el archivo de clase  Constants.java .

Java

public class Constants {
  
    // Texts to show inside the breathing circle
    public static final String INHALE = "INHALE";
    public static final String EXHALE = "EXHALE";
    public static final String HOLD = "HOLD";
  
    // FAB button visibility delay
    public static int CONTENT_SHOW_DELAY_MS = 2000;
  
    // Defaults for @{@link SettingsUtils}
    public static final int DEFAULT_PRESET_INDEX = 0;
    public static final int DEFAULT_DURATION = 6000;
      
    // Value used to convert between animation
    // duration and seekbar unit
    public static final int MILLISECOND = 2000;
}

Cree una nueva enumeración de Java y nombre el archivo como Preset. A continuación se muestra el código para el archivo de clase  Preset.java .

Java

import com.example.breath.R;
  
public enum Preset {
  
    WARM_FLAME(0, R.drawable.bg_circle_preset_warm_flame),
    NIGHT_FADE(1, R.drawable.bg_circle_preset_night_fade),
    WINTER_NEVA(2, R.drawable.bg_circle_preset_winter_neva),
    MORNING_SALAD(3, R.drawable.bg_circle_outer),
    SOFT_GRASS(4, R.drawable.bg_circle_preset_soft_grass);
  
    private final int settingsPosition;
    private final int resId;
  
    Preset(int settingsPosition, int resId) {
        this.settingsPosition = settingsPosition;
        this.resId = resId;
    }
  
    public int getResId() {
        return resId;
    }
  
}

Cree una nueva clase Java y nombre el archivo como SettingsDialog. A continuación se muestra el código para el archivo de clase  SettingsDialog.java .

Java

import android.app.Dialog;
import android.content.Context;
import android.os.Bundle;
import android.support.annotation.IdRes;
import android.support.annotation.NonNull;
import android.view.View;
import android.widget.Button;
import android.widget.RadioButton;
import android.widget.RadioGroup;
import android.widget.SeekBar;
  
import com.example.breath.R;
import com.example.breath.utils.Constants;
import com.example.breath.utils.Preset;
import com.example.breath.utils.SettingsUtils;
  
public class SettingsDialog extends Dialog {
  
    private SettingsChangeListener listener;
  
    private RadioGroup radioGroup;
  
    public SettingsDialog(@NonNull Context context, @NonNull SettingsChangeListener listener) {
        super(context, R.style.Theme_SettingsDialog);
        this.listener = listener;
    }
  
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.v_overlay);
        getWindow().getAttributes().windowAnimations = R.style.Theme_SettingsDialog;
  
        radioGroup = findViewById(R.id.rg_gradients);
        SeekBar inhaleSeekBar = findViewById(R.id.seekBar_inhale);
        SeekBar exhaleSeekBar = findViewById(R.id.seekBar_exhale);
        SeekBar holdSeekBar = findViewById(R.id.seekBar_hold);
        Button closeButton = findViewById(R.id.btn_close);
  
        radioGroup.setOnCheckedChangeListener(checkedChangeListener);
        inhaleSeekBar.setOnSeekBarChangeListener(inhaleSeekBarChangeListener);
        exhaleSeekBar.setOnSeekBarChangeListener(exhaleSeekBarChangeListener);
        holdSeekBar.setOnSeekBarChangeListener(holdSeekBarChangeListener);
        closeButton.setOnClickListener(closeBtnClickListener);
  
        ((RadioButton) radioGroup.getChildAt(SettingsUtils.getSelectedPreset())).setChecked(true);
        inhaleSeekBar.setProgress(SettingsUtils.getSelectedInhaleDuration() / Constants.MILLISECOND);
        exhaleSeekBar.setProgress(SettingsUtils.getSelectedExhaleDuration() / Constants.MILLISECOND);
        holdSeekBar.setProgress(SettingsUtils.getSelectedHoldDuration() / Constants.MILLISECOND);
    }
  
    private RadioGroup.OnCheckedChangeListener checkedChangeListener = new RadioGroup.OnCheckedChangeListener() {
        @Override
        public void onCheckedChanged(RadioGroup group, @IdRes int checkedId) {
            Preset selectedPreset;
            switch (checkedId) {
                case R.id.rb_1:
                    selectedPreset = Preset.WARM_FLAME;
                    break;
                case R.id.rb_2:
                    selectedPreset = Preset.NIGHT_FADE;
                    break;
                case R.id.rb_3:
                    selectedPreset = Preset.WINTER_NEVA;
                    break;
                case R.id.rb_4:
                    selectedPreset = Preset.MORNING_SALAD;
                    break;
                case R.id.rb_5:
                    selectedPreset = Preset.SOFT_GRASS;
                    break;
                default:
                    selectedPreset = Preset.WARM_FLAME;
                    break;
            }
            SettingsUtils.saveSelectedPreset(selectedPreset.ordinal());
            listener.onPresetChanged(selectedPreset.getResId());
        }
    };
  
    private SeekBar.OnSeekBarChangeListener inhaleSeekBarChangeListener = new SeekBar.OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            listener.onInhaleValueChanged(progress != 0 ? progress * Constants.MILLISECOND : Constants.MILLISECOND);
            SettingsUtils.saveSelectedInhaleDuration(progress != 0 ? progress * Constants.MILLISECOND :
                    Constants.MILLISECOND);
        }
  
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }
  
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    };
  
    private SeekBar.OnSeekBarChangeListener exhaleSeekBarChangeListener = new SeekBar
            .OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            listener.onExhaleValueChanged(progress != 0 ? progress * Constants.MILLISECOND : Constants.MILLISECOND);
            SettingsUtils.saveSelectedExhaleDuration(progress != 0 ? progress * Constants.MILLISECOND :
                    Constants.MILLISECOND);
        }
  
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }
  
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    };
  
    private SeekBar.OnSeekBarChangeListener holdSeekBarChangeListener = new SeekBar
            .OnSeekBarChangeListener() {
        @Override
        public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {
            listener.onHoldValueChanged(progress * Constants.MILLISECOND);
            SettingsUtils.saveSelectedHoldDuration(progress * Constants.MILLISECOND);
        }
  
        @Override
        public void onStartTrackingTouch(SeekBar seekBar) {
        }
  
        @Override
        public void onStopTrackingTouch(SeekBar seekBar) {
        }
    };
  
    private View.OnClickListener closeBtnClickListener = new View.OnClickListener() {
        @Override
        public void onClick(View v) {
            dismiss();
        }
    };
  
    public interface SettingsChangeListener {
        void onPresetChanged(int backgroundResId);
  
        void onInhaleValueChanged(int duration);
  
        void onExhaleValueChanged(int duration);
  
        void onHoldValueChanged(int duration);
    }
}

En la ejecución del código, podemos obtener el resultado como se muestra en el video adjunto.

Producción:

Enlace Github: https://github.com/raj123raj/meditation

Publicación traducida automáticamente

Artículo escrito por priyarajtt y traducido por Barcelona Geeks. The original can be accessed here. Licence: CCBY-SA

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *