摘要
假期宅在家里,现在正处于大三,面临找工作和考研的两种选择。但是对找工作其实没有太大的兴趣,于是便准备考研。然后想着手记录一下考研的生活点滴,作为以后的一个回忆。毕竟考研是最后一次可以通过努力来改变学历的机会。然后就在应用市场和小程序搜罗各种各样的打卡app或者小程序。但是都没有符合自己的要求的。于是就萌生了开发一款属于自己的打卡小程序。刚开始做了个一个小程序并且成功发布了。叫做”21天习惯卡“,功能比较简化。但是开发完小程序之后并不满足,于是又萌生了开发安卓的想法。这个安卓并不是普通的安卓,而是通过uniapp开发的安卓,就相当于一个web安卓应用。
如果大家有什么问题可以在凯小白提问。
功能展示,页面展示
主页,加入打卡圈,扫码加入
打卡圈详情,打卡发现也,打卡日历
打卡图标,邀请加圈,发现页面
圈子页,我的页,笔记提交页
每日打卡生成的卡片
功能展示
项目查看
开发过程
从来没有接触过uniapp,这个寒假是第一接触uniapp,但是看着uniapp使用的vue。还是比较方便上手的。
界面设计
dcloud社区提供了很多的插件还有模板,在加上之前也学习过前端。于是就自己绘制设计稿。纯手绘,所以这里就不跟大家展示了。先想了一下功能,然后绘制样式,指定某个部位点击跳转到某个页面。其实说着简单,画起来是真不容易。因为逻辑啥的要考虑清楚,包括页面传参,参数也不能出错,每个页面跳转需要的参数也是不同的。
功能设计
预期设想的功能:
1.打卡圈:分为两种,公共打卡圈,私人打卡圈。私人打卡圈可以设置是否可以被公共访问
2.每日打卡:刚开始想的是只有打卡内容,没考虑打卡图片的功能。后来发现没有上传图片不太完善, 于是加入打卡上传功能。
3.打卡日历:查看每日打卡
4.打卡图表:查看打卡数据
5.图文圈子:可以公开发布自己的内容,可被推荐至全部人查看。
后期新加的功能:
积分功能:为了以后的资源分享app做准备。
会员功能:根据积分的多少自动评定,不收费,也是为了资源app做准备。
匿名发泄:在我们坚持习惯的时候,总会有很多的琐事来打扰我们,而我们也无从去发泄,于是就开发了匿名发泄的功能,在这里头像和昵称都是随机生成的没人知道是谁发泄的,但是说出来总归是好的。
(发泄评论功能还在开发中)
后台开发
后台采用Java语言,数据库采用mysql,挂载在阿里云服务器上。
前端开发
使用了两个大佬的组件库的一些内容,同时也自己开发了一些页面。同时也根据自己的需要二次开发了大佬的组件库
安卓app一些功能的实现
安卓登录状态保存
引入store
首先在main.js中加入如下一句话,引入store
import store from './store'
然后创建store目录,创建index.js文件,在里面写入
import Vue from 'vue'
import Vuex from 'vuex'
Vue.use(Vuex)
const store = new Vuex.Store({
state: {
/**
* 是否需要强制登录
*/
forcedLogin: false,
hasLogin: false,
userinfo:{}
},
mutations: {
login(state, userinfo) {//登录方法
state.userinfo = userinfo;
state.hasLogin = true;
uni.setStorage({
key: 'userinfo',//登录用户的信息
data: userinfo
})
uni.setStorage({
key:'hasLogin',//登录状态
data:true
})
},
logout(state) {//注销登录方法
state.userinfo = {};
state.hasLogin = false;
uni.removeStorage({
key: 'userinfo'//抹除登录用户信息
});
uni.removeStorage({
key:'hasLogin'//抹除登录状态
})
}
}
})
export default store
完成之后,则需要在使用该方法的页面加入
import {
mapState,
mapMutations
} from 'vuex';
...mapMutations(['login']) //登录页面引入
...mapMutations(['logout']) //注销页面引入
页面获取登录用户的信息
uni.getStorage({
key: 'userinfo',//获取缓存中的用户信息
success(e) {
that.openid=e.data.openid//用户的唯一标志
console.log(e.data)
if (e.data) {
uni.request({
url: 'url',//获取数据的url
data: {
},
method: 'POST',
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
success: (res) => {},
fail: () => {
uni.showModal({
title:'您好,系统正在维护中'
})
}
})
}else {
uni.navigateTo({//获取失败返回登录界面
url: '../login/login'
})
}
})
下拉刷新功能
uniapp和小程序一样,需要开启onpulldownrefresh
在pages.json内的对应页面的style中加入
"enablePullDownRefresh": true, // 开启下拉
"backgroundTextStyle": "dark"
然后在页面内的onPullDownRefresh方法中加入需要刷新数据的请求接口
onPullDownRefresh() {
var that=this
uni.request({
url: 'url',
data: {
},
method: 'POST',
header: {
"Content-Type": "application/x-www-form-urlencoded"
},
success: (res) => {
uni.stopPullDownRefresh()
}
})
},
打卡卡片
作为一个打卡app,打卡卡片的生成至关重要,虽然不是所有人都会去保存这个打卡卡片。
但是打卡卡片是我们打卡完成的唯一证据。
绘制卡片
var now = new Date();
var year = now.getFullYear(); //年
var month = now.getMonth() + 1; //月
var day = now.getDate();
var hour=now.getHours();
var minute=now.getMinutes();
var reallywight=uni.getSystemInfoSync().windowWidth
var reallyhight=uni.getSystemInfoSync().windowHeight
var wigth=uni.getSystemInfoSync().windowWidth-50
var hight=uni.getSystemInfoSync().windowHeight-90
var height=uni.getSystemInfoSync().windowHeight-190
const ctx =uni.createCanvasContext('myCanvas');
ctx.drawImage( "../../static/cards/card19.png" , 25 ,25 ,wigth,wigth*1.77 ); //绘制图
ctx.save()
ctx.setFillStyle("#FFFFFF")
ctx.font = 'normal 16px sans-serif';
ctx.fillText("每/",wigth-80,70)
ctx.fillText("日/",wigth-56,70)
ctx.fillText("一/",wigth-32,70)
ctx.fillText("签",wigth-8,70)
var nowtime=hour+":"+minute
ctx.fillText(nowtime,wigth-56,100)
ctx.setFillStyle("#FFFFFF")
ctx.setFontSize(50)//设置字体大小,默认10
ctx.textAlign = 'center' // 设置位置
ctx.font = 'normal 40px sans-serif'; // 字体样式
ctx.fillText(day , 60, 80);
ctx.font = 'normal 15px sans-serif';
ctx.fillText("⛪枣庄市",70,120)
ctx.font = 'normal 10px sans-serif';
ctx.fillText("21天习惯打卡",60, wigth*1.70-45)
ctx.save()
ctx.font = 'normal 12px sans-serif';
var dayy=year+"."+month
ctx.fillText(dayy,60,100)
ctx.save()
var text="所有的习惯以,不可见的程度积聚起来,如百溪汇于川,百川流于海!"
ctx.font = '30px FZShuTi';
var str= new Array();
str=text.split(",");
// ctx.textAlign="center";
var uphight=0
for (var i=0;i<str.length;i++){
ctx.font = '30px shuti';
ctx.fillText(str[i], reallywight/2, height/2+uphight)
uphight+=40
}
ctx.font = 'normal 20px FZYaoti';
ctx.fillText("考研记录生活圈子",wigth-80,wigth*1.70-25)
ctx.font = 'normal 20px FZYaoti';
ctx.fillText("已打卡10天",wigth-50,wigth*1.77-15)
ctx.draw()
卡片适配问题
屏幕问题
两种实现方法。
一,适用于文字长度不知道,也不知道具体输出的问题
将文字拆分,先得到字符串的长度,然后通过split分割。
通过循环串接字符串,当到达设定的宽度的时候自动绘制,然后字符串清空,继续串接
直到绘制到最后一行。
二,文字内容我们已经事先得知
当我们开发一些打卡app的时候,输出的内容我们都是规定好的,随机生成我们数组内的字符串,这个时候就可以规定字符串内的拆分符号
在我的开发中,我是在20句名言中随机生成一个句子,内容已经知道,于是采用了第二种开发方式
var text="所有的习惯以,不可见的程度积聚起来,如百溪汇于川,百川流于海!"//假设是随机生成的橘子
ctx.font = '30px FZShuTi';
var str= new Array();
str=text.split(","); //拆分句子
// ctx.textAlign="center";
var uphight=0
for (var i=0;i<str.length;i++){
ctx.font = '30px shuti';
ctx.fillText(str[i], reallywight/2, height/2+uphight)
uphight+=40
}