喝水提醒app

Aqua Reminder

简要介绍

这是我们人机交互课程的大作业,任务是设计一个简单的app,要求符合人机交互目标。我们设计了一个喝水提醒app—Aqua Reminder,该app是模仿柠檬喝水app实现的。功能有每日喝水量显示喝水量添加喝水提醒种植树木用户排名等。我花了较长的时间学习Android方面的一些知识,在下面会介绍app中用到的一些知识。

功能介绍

  • 每日喝水量显示:
    • 喝水的水杯中会显示今日的喝水量
    • 水杯中的水量不会超过1500ml
  • 喝水量添加:
    • 喝完水后可以添加本次喝水量
    • 一天过去将会更新喝水量
  • 喝水提醒:
    • 定时提醒:闹钟将会在规定的时间提醒
    • 间隔提醒:闹钟将在设置后每隔一小时提醒
  • 种植树木:
    • 用户可以在种植界面兑换树木种子
    • 兑换后树木可以在已种植中查看
  • 用户排名:
    • app将会按照能量多少将所有用户排名
  • 给个好评:
    • 用户可以给app打分
  • 个人信息:
    • 用户可以看到个人信息,包括各种数据

主要页面展示

登录界面:

喝水界面:

添加喝水量界面:

提醒设置界面:

种植树木界面:

选择树木界面:

已种植界面:

用户界面:

用户排名界面:

给个好评界面:

个人信息界面:

技术简介

  • ListView顶部和底部的分割线:

    ListView lv;
    lv.addHeaderView(new View(this)); // 添加顶部分割线
    lv.addFooterView(new View(this)); // 添加底部分割线
    
  • 返回上一级:

    Activity.this.finish();
    
  • 对话框:

    AlertDialog alert = null;
    AlertDialog.Builder builder = null;
    
    alert = null;
    builder = new AlertDialog.Builder(Activity.this);
    // 标题+消息+按钮
    alert = builder.setTitle("...").setMessage("...").setNegativeButton("...", new DialogInterface.OnClickListener() {
        @Override
        public void onClick(DialogInterface dialog, int which) {
    
        }
    }).create();
    alert.show();
    
  • 闹钟提醒:

    Android官方文档

  • 底部导航栏:

    菜鸟教程

  • 视图滑动:

    ViewPager

  • 水杯水量动态变化:

    Histogram类:

    public class Histogram extends View {
    
        int MAX = 1800; // 矩形显示的最大值
        int corner = 0; // 矩形的角度,设置为0则没有角度。
        double data = 0; // 显示的数
        double tempData = 0; // 初始数据
        int textPadding = 0; // 字体与矩形图的距离
        Paint mPaint;
        int mColor;
        Context mContext;
    
        //构造函数
        public Histogram(Context context) {
            super(context);
            mContext = context;
        }
    
        public Histogram(Context context, @Nullable AttributeSet attrs) {
            super(context, attrs);
            mContext = context;
            initPaint();
        }
    
        public Histogram(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
            super(context, attrs, defStyleAttr);
            mContext = context;
            initPaint();
        }
    
        // 画笔方法
        private void initPaint() {
            mPaint = new Paint();
            mPaint.setAntiAlias(true);
            mColor = mContext.getResources().getColor(R.color.water);
            mPaint.setColor(mColor);
        }
    
        @Override
        public void draw(Canvas canvas) {
            super.draw(canvas);
            if (data == 0.0) {
                mPaint.setTextSize(getWidth() / 2);
                RectF oval3 = new RectF(0, getHeight() - DensityUtils.pxTodip(mContext,
                        20), getWidth(), getHeight()); // 设置个新的长方形
                canvas.drawRoundRect(oval3, DensityUtils.pxTodip(mContext, corner),
                        DensityUtils.pxTodip(mContext, corner), mPaint);
                canvas.drawText("",
                        getWidth() * 0.5f - mPaint.measureText("0") * 0.5f,
                        getHeight() - DensityUtils.pxTodip(mContext, 20) -
                                2 * DensityUtils.pxTodip(mContext, textPadding),
                        mPaint);
                return;
            }
    
            // 防止数值很大的的时候,动画时间过长
            int step = (int) (data / 100 + 1.0);
            if (tempData < data - step) {
                tempData = tempData + step;
            } else {
                tempData = data;
            }
            //画圆角矩形
            String S = tempData + ""; // 如果数字后面需要加% 则在""中添加%
            // 设置显示的字体
            // Typeface typeface = Typeface.createFromAsset(getContext().getAssets(),"digital-7.ttf");
            // mPaint.setTypeface(typeface);
            // 一个字和两,三个字的字号相同
            if (S.length() < 4) {
                mPaint.setTextSize(getWidth() / 2);
            } else {
                mPaint.setTextSize(50); // 可以通过getWidth()/2 改变字体大小 也可以通过设置数字来改变自己想要的字体大小 当超出矩形图宽度时不能显示全部
            }
    
            float textH = mPaint.ascent() + mPaint.descent();
            float MaxH = getHeight() - textH - 2 * DensityUtils.pxTodip(mContext, textPadding);
    
            // 圆角矩形的实际高度
            float realH = (float) (MaxH / MAX * tempData);
            RectF oval3 = new RectF(0, getHeight() - realH, getWidth(), getHeight()); // 设置个新的长方形
            canvas.drawRoundRect(oval3, DensityUtils.pxTodip(mContext, corner), DensityUtils.pxTodip(mContext, corner), mPaint);
            // 写数字
            canvas.drawText(S,
                    getWidth() * 0.5f - mPaint.measureText(S) * 0.5f,
                    getHeight() - realH - 2 * DensityUtils.pxTodip(mContext, textPadding),
                    mPaint);
    
            if (tempData != data) {
                postInvalidate();
            }
        }
    
        public void setData(double tempData, double data, int MAX) {
            this.tempData = tempData;
            this.data = data;
            this.MAX = MAX;
            postInvalidate();
        }
    
    }
    

    某个Activity或Fragment:

    private Histogram histogram;
    
    histogram.setData(tempWater, water, MAX_WATER);
    

    别忘了在页面中定义一个Histogram控件

  • SwitchCompat开关:

    类名:androidx.appcompat.widget.SwitchCompat

存在的问题

(已解决)app中使用了BroadcastReceiver来监听日期发生变化,但是一直出现了onReceive方法多次调用导致数据库中的数据更新有错误的问题,该问题一直没有解决,如果有解决的方法欢迎评论或者私信。

代码如下:

dateChangeReceiver = new BroadcastReceiver() {
    @Override
    public void onReceive(Context context, Intent intent) {
        String action = intent.getAction();
        if (action.equals(Intent.ACTION_DATE_CHANGED) && broadcastFlag) {
        broadcastFlag = false;
        updateUserInfo();
        flag = true;
    	}
    	else {
        broadcastFlag = true;
    	}
	}
};

IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(Intent.ACTION_DATE_CHANGED);
registerReceiver(dateChangeReceiver, intentFilter);

解决方案:

原先我是在onCreate方法中创建dateChangeReceiver对象的,但我并没有及时关闭导致对象被创建多次,所以onReceive方法多次调用。

所以我改为在onResume方法中新建对象,并在onPause方法中注销接收器。

代码如下:

	@Override
    protected void onResume() {
        super.onResume();
        dateChangeReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {
                String action = intent.getAction();
                if (action.equals(Intent.ACTION_DATE_CHANGED)) {
                    flag = true;
                    updateUserInfo();
                }
            }
        };
        IntentFilter intentFilter = new IntentFilter();
        intentFilter.addAction(Intent.ACTION_DATE_CHANGED);
        registerReceiver(dateChangeReceiver, intentFilter);
    }

	@Override
    protected void onPause() {
        super.onPause();
        unregisterReceiver(dateChangeReceiver);
    }

项目地址

gitee地址

github地址

  • 2
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
App开发签到提醒的主要目的是帮助用户记录和管理签到活动,并提供准时提醒的功能。以下是关于这个功能的详细回答: 首先,在App开发签到提醒功能,用户可以创建自己的签到计划并设定提醒时间。用户可以根据个人需求选择是每天、每周还是某个特定的日期进行签到。用户还可以设定提前提醒的时间,以确保不会忘记签到。这样,用户就能轻松管理自己的签到计划,并准时参与相应活动。 其次,App开发签到提醒功能还可以实现精确的位置提醒。用户可以使用GPS定位功能设定签到地点,并设置签到半径。当用户接近签到地点时,App会自动发送提醒,以确保用户及时完成签到。这对于需要在特定地点签到的活动非常有用,比如会议、研讨会或课程。 除此之外,App开发签到提醒功能还可以提供签到统计和数据分析功能。用户可以查看自己的签到历史记录,了解自己的签到情况。这样,用户就可以对自己的签到习惯进行分析和改善。App还可以提供数据图表,展示签到趋势和统计信息,帮助用户更好地了解自己的签到活动。 对于组织者而言,App开发签到提醒功能还可以方便管理和统计签到情况。组织者可以使用App导入签到名单,根据参与者的签到情况实时统计出席人数。这对于会议、培训班、活动报名等组织者来说非常有用,能够提高工作效率和准确性。 综上所述,App开发签到提醒功能在签到活动的记录、管理和提醒方面提供了很多便利,满足了用户和组织者的需求,为签到活动带来更好的体验。
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值