📌  相关文章
📜  如何为呼吸运动构建一个简单的Android应用程序?

📅  最后修改于: 2021-05-10 14:59:40             🧑  作者: Mango

Android手机非常方便,并且可以即时提供信息。只是假设您经常在连续飞行或参加患者或参加会议等。在那段时间里,可能会有压力,因此冥想在这种快速的生活中非常重要。这里提供了呼吸运动应用程序的源代码,并且肯定会有助于变得更有活力和热情。下面给出了一个示例GIF,以使我们对本文中要做的事情有一个了解。注意,我们将使用Java语言实现该项目。

构建一个简单的Android应用来呼吸GIF呼吸示例

分步实施

步骤1:创建一个新项目

要在Android Studio中创建新项目,请参阅如何在Android Studio中创建/启动新项目。请注意,选择Java作为编程语言。

第2步:首先进入编码部分,您必须做一些准备工作

转到应用程序> res>值> colors.xml文件,然后为您的应用程序设置颜色。

XML


    #5db839
    #0F9D58
    #0F9D58
    #FF4081


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'
}


XML


  
    
  


XML


  
    
  
    
  
    
  


XML


    


XML


  
    
  


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;
    }
}


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;
    }
}


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();
    }
}


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;
}


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;
    }
  
}


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);
    }
}


转到Gradle脚本> build.gradle(模块:应用程序)文件并导入以下依赖项,然后在上面的弹出窗口中单击“立即同步”。

以下是build.gradle(模块:app)文件的完整代码:

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'
}

步骤3:设计UI部件

使用activity_main.xml文件:

转到activity_main.xml文件,并参考以下代码。以下是activity_main.xml文件的代码。

XML格式



  
    
  

这里,包含了content_main.xml 。下面是它的代码:

XML格式



  
    
  
    
  
    
  

您可以在上面的代码中看到“ bg_circle_inner ”和“ bg_circle_outer ”。我们需要在drawable文件夹中创建(转到drawable>右键单击> New> Drawable Resource File )。

以下是bg_circle_inner.xml文件的代码:

XML格式



    

以下是bg_circle_outer.xml文件的代码:

XML格式



  
    
  

基本上, bg_circle_outer.xml和bg_circle_inner.xml是创建椭圆形的XML文件,它们在content_main.xml中使用。它们的目的是显示“吸气”和“呼气”的目的。

步骤4:使用Java文件

使用MainActivity。 Java文件:

转到MainActivity。 Java文件并参考以下代码。下面是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;
    }
}

创建一个新的Java类,并将文件命名为SettingsUtils。以下是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;
    }
}

创建一个新的Java类,并将文件命名为BreathePreferences。下面是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();
    }
}

创建一个新的Java类,并将文件命名为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;
}

创建一个新的Java Enum并将文件命名为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;
    }
  
}

创建一个新的Java类,并将文件命名为SettingsDialog。下面是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);
    }
}

执行代码后,我们可以获取输出,如随附的视频所示。

输出:

Github链接: https : //github.com/raj123raj/meditation

想要一个节奏更快,更具竞争性的环境来学习Android的基础知识吗?
单击此处,前往由我们的专家精心策划的指南,以使您立即做好行业准备!