仿DayGram项目复盘

1. DayGram是什么

DayGram:用纸墨的形式记录生活的点滴
AppStoreGoogle 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和当篇日记的年yearmonthday以及内容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基础,然后界面布局又花了一周的时间,逻辑写了两周。中途一度想过放弃,甚至怀疑自己是不是该换专业,不过还好坚持下来了。现在想想,收获还是很多,最重要的是增强了自己编程的信心,再复杂的功能通过自己的慢慢摸索也是能做出来的,加油!

下面是我开发过程中查阅的部分资料
  1. drawable文件夹的用途

    drawable用来存放图片,mimap开头的文件用来存放应用图标

  2. android:shape的使用

    drawable文件夹下面不仅可以放图片,还可以放xml文件,其中xml文件主要通过shape生成图像控件,

    android:shape的使用1

    shape使用2

  3. NumberPicker的用法

    数值选择器(NumberPicker)的功能与用法

  4. layer-list的用法

    layer-list

  5. 获得某一个月的天数

    天数

  6. 根据年月日获得星期数

  7. 通过intent传递数据

  8. TextView的背景为圆

  9. Android控件显示和隐藏

  10. 控件实现叠加效果

  11. Recyclerview实现回调函数

  12. string和int进行转换

  13. List里面的对象按照指定字段排序

获取源码:源码(包含效果演示)

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值