1. DayGram是什么
DayGram:用纸墨的形式记录生活的点滴
在AppStore
和Google Play
上面均有下载,下载地址:IOS,Androoid
如果想要获取源码,请直接滑到底部
2. 界面设计
首先明确,本项目包括两个Activity,每个Activity包括两种形态。主页面的Activity包括两个listview形式,编辑界面的Activity包括查看模式和编辑模式
主界面列表
主界面包括两个listview,两者除了id和visibility不同以外,其余都相同,
<ListView
android:id="@+id/entryListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:layout_marginTop="0dp"
android:layout_marginBottom="50dp"
android:divider="@null"
android:dividerHeight="0dp"
android:visibility="visible"/>
<ListView
android:id="@+id/DiaryListView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:layout_gravity="top"
android:layout_marginTop="0dp"
android:layout_marginBottom="50dp"
android:divider="@null"
android:dividerHeight="0dp"
android:visibility="invisible"/>
边框斜线实现
思路:将斜线作为整个背景,然后上面覆盖一层比外层略窄的内容层即可
背景:
<?xml version="1.0" encoding="utf-8"?>
<layer-list xmlns:android="http://schemas.android.com/apk/res/android">
<item>
<bitmap android:src="@drawable/stripe"
android:tileMode="repeat"
android:dither="true"
>
</bitmap>
</item>
<item>
<shape
android:shape="rectangle">
<stroke android:width="2dp" android:color="#000"/>
</shape>
</item>
</layer-list>
3. 技术实现
文件存储
使用的数据库方式存储,并且使用的是一个开源库,LitePal(具体使用方法参考《第二行代码》6.5节)
数据库里面的字段包括id
和当篇日记的年year
月month
日day
以及内容content
/*
* 设置数据表里面的字段
* */
public class Diary extends DataSupport {
private int id;
private String year;
private String month;
private String day;
private String week;
private String content;
.....
}
当用户点击DONE
之后,该篇日记插入数据库,并且我在其中加入了两个判定
- 判定内容非空,才进行下一步操作
- 判定数据库无同年同月同日的数据,才进行插入操作,否则进行更新操作
并且最后返回主页面的时候,将本页面的年和月传了回去,保证回到的是编写日记所在的界面,而不用每次都回到同一界面
//数据插入数据库
class InsertValue implements View.OnClickListener{
@Override
public void onClick(View v) {
boolean exit=false;//用来判断数据库是否有相同的数据
value=editorText.getText().toString();//获取内容
Diary diarys=new Diary();
List<Diary> diaries=DataSupport.findAll(Diary.class);
if(value.length()!=0){//有内容才进行存储或者更新操作
//判断是否库中是否有同年月日的数据
for(Diary diary:diaries){
if(year_string.equals(diary.getYear())&&month_string.equals(diary.getMonth())&&day.equals(diary.getDay())){
diarys.setContent(value);
diarys.updateAll("year=? and month=? and day=?",year_string,month_string,day);
exit=true;
break;//更新
}
}
//数据库中没有同年月日的数据,再添加
if(exit==false){
diarys.setContent(value);
diarys.setDay(day);
diarys.setYear(year_string);
diarys.setMonth(month_string);
Log.d(tag,"week_day:"+week_day);
diarys.setWeek(week_day);
diarys.save();//第一次存储
}
}
//回到主界面
Intent intent=new Intent(EditorActivity.this,MainActivity.class);
//向主页面传年和月,来保证回到日记所在的年和月主界面
intent.putExtra("month",String.valueOf(month));
intent.putExtra("year",year_string);
startActivity(intent);
}
}
只要数据存进了数据库,接下来就是运用的问题了,首先为了生成详细信息列表界面,我从数据库中读出同年和月的数据,并且按照日子day
升序的方式排列
//生成日志列表数据
private void initDiaries(){
List<Diary> diaries=DataSupport.findAll(Diary.class);
diaryList.clear();//每次前清空;
change_month();//因为我的数据库里面month存储的数据是英文,这里将月份从汉字转换成英文
//从数据库里面查数据
for(Diary diary:diaries){
//查找同年和月的数据
if(year.equals(diary.getYear())&&month_Eng.equals(diary.getMonth())){
DiaryShow diaryshow=new DiaryShow(diary.getDay(),diary.getWeek(),diary.getContent());
diaryList.add(diaryshow);
}
}
//对diaryList进行按照day升序的形式排序
Collections.sort(diaryList, new Comparator<DiaryShow>() {
@Override
public int compare(DiaryShow o1, DiaryShow o2) {
if(Integer.parseInt(o1.getDay())>Integer.parseInt(o2.getDay())){
return 1;
}else if(Integer.parseInt(o1.getDay())==Integer.parseInt(o2.getDay())){
return 0;
}else
return -1;
}
});
}
编辑界面标题显示
思路:标题的年月日全部由主界面传递过来,然后星期数通过年月日算出来
计算星期数
//通过年月日获得星期数
public static void CalculateWeekDay(int y, int m, int d) {
if (m == 1 || m == 2) {
m += 12;
y--;
}
int iWeek = (d + 2 * m + 3 * (m + 1) / 5 + y + y / 4 - y / 100 + y / 400) % 7;
switch (iWeek) {
case 0:
week=1;
break;
case 1:
week=2;
break;
case 2:
week=3;
break;
case 3:
week=4;
break;
case 4:
week=5;
break;
case 5:
week=6;
break;
case 6:
week=7;
break;
}
}
传递数据
注意这里的day
(号数)是通过position
计算出来的
listView2.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
Intent intent=new Intent(MainActivity.this,EditorActivity.class);
DiaryShow diary=diaryList.get(position);
//将主界面的年月日传过去
intent.putExtra("day_time1",diary.getDay());
intent.putExtra("year_time",year);
intent.putExtra("month_time",month);
startActivity(intent);
}
});
接收数据并显示
private void TitleTime() {
//通过主页面传过来的天数
Intent intent=getIntent();
String day_int_string=intent.getStringExtra("day_time1");//从列表2传过来的日子
if(day_int_string==null) {
day = intent.getStringExtra("day_time");//从列表1传过来的日子
day_int=Integer.parseInt(day);
day_int+=1;//获得int类型的日子数,并且记得后面要+1
//再把string类型的天数+1
}else {
day_int=Integer.parseInt(day_int_string);
}
year_string=intent.getStringExtra("year_time");
month_string=intent.getStringExtra("month_time");
//更新字符型年月日
year=Integer.parseInt(year_string);
month=Integer.parseInt(month_string);
day=String.valueOf(day_int);
CalculateWeekDay(year,month,day_int);//获得星期数
change_week_month();
//将标题拼接起来
TitleTime=week_day+"/"+month_string+" "+day_int+"/"+year;//设置格式
editorHeaderTitle.setText(TitleTime);
}
3.2底部月份和年份选择器
思路:通过RecyclerView
实现,然后和底部菜单栏一个显示一个隐藏即可
年份选择器:
private void bottom_recyclerview_year(){
initYear();
final RecyclerView recyclerView=(RecyclerView)findViewById(R.id.recyccler_view_year);
LinearLayoutManager layoutManager=new LinearLayoutManager(this);
//通过layoutManager来设置水平布局
layoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
recyclerView.setLayoutManager(layoutManager);
MonthAdapter adapter=new MonthAdapter(yearList);
//设置点击事件
adapter.onClickListener(new MonthAdapter.onItemClick() {
@Override
public void onClick(View v, int i) {
//i从1开始,设置的年份从2012开始,所以i+2011
year_int=i+2011;
year=String.valueOf(year_int);
labelYear.setText(year);
StartListView();//更新列表
StartDiaryListView();
recyccler_view_year.setVisibility(View.INVISIBLE);
bottom_menum.setVisibility(View.VISIBLE);
}
});
recyclerView.setAdapter(adapter);
}
年份适配器:
public class MonthAdapter extends RecyclerView.Adapter<MonthAdapter.ViewHolder> {
private List<Month> MonthList;
private onItemClick listener;
public interface onItemClick{
void onClick(View v,int i);
}
public void onClickListener(onItemClick listener){
this.listener = listener;
}
static class ViewHolder extends RecyclerView.ViewHolder{
TextView MonthName;
public ViewHolder(View view){
super(view);
MonthName=view.findViewById(R.id.month_name);
}
}
public MonthAdapter(List<Month> monthList){
MonthList=monthList;
}
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType){
View view= LayoutInflater.from(parent.getContext()).inflate(R.layout.month_item,parent,false);
final ViewHolder holder=new ViewHolder(view);
holder.MonthName.setOnClickListener(new View.OnClickListener(){
@Override
public void onClick(View view) {
int position=holder.getAdapterPosition();
listener.onClick(view,position);
}
});
return holder;
}
@Override
public void onBindViewHolder(ViewHolder holder,int position){
Month month=MonthList.get(position);
holder.MonthName.setText(month.getMonth());
}
@Override
public int getItemCount(){
return MonthList.size();
}
}
查看模式与编辑模式
思路:先隐藏光标,设置小白条(返回键)和底部菜单栏一个显示一个隐藏,当点击时,显示光标,对换显示和隐藏状态即可
editorText.setOnTouchListener(new View.OnTouchListener() {
@SuppressLint("ClickableViewAccessibility")
@Override
public boolean onTouch(View v, MotionEvent event) {
if (MotionEvent.ACTION_DOWN == event.getAction()) {
editorText.setCursorVisible(true);// 再次点击显示光标
editorFooterDone.setVisibility(View.VISIBLE);
buttonBack.setVisibility(View.INVISIBLE);
}
return false;
}
});
图标说明
- 原版
说明:
黑点:表示当天无日记,并且不是星期天
红点:表示当天无日记,并且是星期天 - 我的版本
说明:
黑点:当天无日记,并且不是星期天
红点:当天无日记,并且是星期天
蓝书:当天有内容,不是星期天
红书:当天有内容,并且是星期天
这样设计的理由:
乍一看似乎很难理解,不如原版那样生动形象,但我认为既然有两种显示列表,那么这两种列表就应该承担不同的角色,
列表一(如上)负责的是简略的显示本月哪几天有日记,并且通过红色标注星期天来间隔每一周即可
列表二(如下)负责的是详细的显示本月日记的内容,并且这里面我同样将星期天标红来间隔每周
隐藏标题和状态栏
删除功能
思路:将EditText里面的内容设为空,并且删除数据库里面相同年月日的数据
class DeleteData implements View.OnClickListener{
@Override
public void onClick(View v) {
editorText.setText("");//表层删除
DataSupport.deleteAll(Diary.class,"year=? and month=? and day=?",year_string,month_string,day);//深层次删除
}
}
日记数量限制
思路:判定当前设置的日期与当前日期的关系,如果在这之前,那通过一个月该多少就多少天,如果就在当月,那么日记只能到当天结束,如果在这之后,那么可以显示的日记数为0
if(year_int<year_today||(year_int==year_today&&month_int<month_today)){
monthNum=getMonthOfDay(year_int,month_int);
}else if(year_int==year_today&&month_int==month_today){
monthNum=day_today;
} else{
monthNum=0;
}
4.总结:
本次实验耗时巨长,前后大概花了一个月吧,主要原因是自己java基础太差,花了一周补java基础,然后界面布局又花了一周的时间,逻辑写了两周。中途一度想过放弃,甚至怀疑自己是不是该换专业,不过还好坚持下来了。现在想想,收获还是很多,最重要的是增强了自己编程的信心,再复杂的功能通过自己的慢慢摸索也是能做出来的,加油!
下面是我开发过程中查阅的部分资料
-
drawable文件夹的用途
drawable用来存放图片,mimap开头的文件用来存放应用图标
-
android:shape的使用
drawable文件夹下面不仅可以放图片,还可以放xml文件,其中xml文件主要通过shape生成图像控件,
-
NumberPicker的用法
-
layer-list的用法
-
获得某一个月的天数