文章目录
- 案例说明
- 实现
- 案例视频
- UI效果
- activity_main.xml文件代码
- tostrings.xml文件代码
- 书本类Book
- 用户类Person
- 初始化控件findViews()
- 初始化数据initData()
- 添加监听器setListeners()
- mNameEditText监听器
- mLendEditText监听器
- mSexRadioGroup监听器
- 三个CheckBox的监听器
- SeekBar监听器
- mQueryButton监听器
- mNextButton监听器
案例说明
这个是我初学Android开发的时候用Java做的一个借书Demo,因为没有学数据库所以不包含数据库相关的技术,直接在代码中完成书籍的实例化操作
实现
- 完成UI界面搭建
- 完成书籍的查找并显示功能
- 完成书籍信息的“下一页”显示功能
- 完成借书时间判断功能
- 输入的时间格式要按照演示视频的格式输入,并将输入的时间格式化成(yyyy-MM-dd)的形式
- 判断日期,如果借出日期晚于还书日期,则弹出提示信息并调用finish()方法实现页面的关闭,当输入时间符合要求时则能正确查找图书
案例视频
UI布局
布局约束用的是线性布局LinearLayout,这一块基本没有什么难度,无非就是各个LinearLayout之间控制好权重属性android:layout_weight,具体的细节完全按照自己喜好来就可以
UI效果
activity_main.xml文件代码
<?xml version=\"1.0\" encoding=\"utf-8\"?><LinearLayout xmlns:android=\"http://schemas.android.com/apk/res/android\"android:layout_width=\"match_parent\"android:layout_height=\"match_parent\"android:background=\"#FFB4EA\"android:orientation=\"vertical\"><TextViewandroid:layout_width=\"match_parent\"android:layout_height=\"wrap_content\"android:layout_margin=\"10dp\"android:text=\"@string/title\"android:textColor=\"#AA5E91\"android:textSize=\"26sp\"android:textStyle=\"bold\" /><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_weight=\"1\"android:orientation=\"vertical\"><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_marginTop=\"10dp\"android:layout_weight=\"1\"android:gravity=\"center_vertical\"android:orientation=\"horizontal\"><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"10dp\"android:text=\"@string/nametext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><EditTextandroid:id=\"@+id/nameEditText\"android:layout_width=\"0dp\"android:layout_height=\"match_parent\"android:layout_marginLeft=\"30dp\"android:layout_weight=\"1\"android:hint=\"@string/inputname_hint\"android:textSize=\"14dp\" /><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"20dp\"android:text=\"@string/sextext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><RadioGroupandroid:id=\"@+id/sexRadioGroup\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:orientation=\"horizontal\"><RadioButtonandroid:id=\"@+id/male\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/male\"android:textSize=\"18sp\" /><RadioButtonandroid:id=\"@+id/female\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/female\"android:textSize=\"18sp\" /></RadioGroup></LinearLayout><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_weight=\"1\"android:gravity=\"center_vertical\"android:orientation=\"horizontal\"><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"10dp\"android:text=\"@string/lendtimetext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><EditTextandroid:id=\"@+id/lendEditText\"android:layout_width=\"0dp\"android:layout_height=\"match_parent\"android:layout_weight=\"1\"android:hint=\"@string/inputlendtime_hint\"android:textSize=\"14dp\" /><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/returntimetext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><TextViewandroid:id=\"@+id/returnTime\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/returntime\"android:textSize=\"16sp\" /></LinearLayout><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_weight=\"1\"android:gravity=\"center_vertical\"android:orientation=\"horizontal\"><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"10dp\"android:text=\"@string/hobbytext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><CheckBoxandroid:id=\"@+id/hisCheckBox\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginRight=\"10dp\"android:text=\"@string/historytext\"android:textSize=\"18sp\" /><CheckBoxandroid:id=\"@+id/susCheckBox\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginRight=\"10dp\"android:text=\"@string/suspensetext\"android:textSize=\"18sp\" /><CheckBoxandroid:id=\"@+id/litCheckBox\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/literaturetext\"android:textSize=\"18sp\" /></LinearLayout><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_weight=\"1\"android:gravity=\"center_vertical\"android:orientation=\"horizontal\"><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"10dp\"android:text=\"@string/agetext\"android:textSize=\"18sp\"android:textStyle=\"bold\" /><TextViewandroid:id=\"@+id/seekBar_ageTextView\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"20dp\"android:textSize=\"18sp\" /><SeekBarandroid:id=\"@+id/seekBar\"android:layout_width=\"0dp\"android:layout_height=\"wrap_content\"android:layout_marginLeft=\"30dp\"android:layout_marginRight=\"30dp\"android:layout_weight=\"1\" /><TextViewandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginRight=\"10dp\"android:text=\"@string/age_100\"android:textSize=\"18sp\" /></LinearLayout><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_marginLeft=\"10dp\"android:layout_marginRight=\"10dp\"android:layout_weight=\"3\"android:background=\"#FFD4EE\"android:orientation=\"horizontal\"><ImageViewandroid:id=\"@+id/bookImageView\"android:layout_width=\"250dp\"android:layout_height=\"wrap_content\"android:src=\"@mipmap/f\" /><LinearLayoutandroid:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:orientation=\"vertical\"android:paddingTop=\"10dp\"><TextViewandroid:id=\"@+id/bookNameTextView\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginBottom=\"15dp\"android:text=\"@string/bookname\"android:textSize=\"16sp\" /><TextViewandroid:id=\"@+id/bookKindTextView\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:layout_marginBottom=\"15dp\"android:text=\"@string/kind\"android:textSize=\"16sp\" /><TextViewandroid:id=\"@+id/bookAgeTextView\"android:layout_width=\"wrap_content\"android:layout_height=\"wrap_content\"android:text=\"@string/age\"android:textSize=\"16sp\" /></LinearLayout></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width=\"match_parent\"android:layout_height=\"0dp\"android:layout_weight=\"1\"android:orientation=\"horizontal\"android:padding=\"10dp\"><Buttonandroid:id=\"@+id/queryBtn\"android:layout_width=\"100dp\"android:layout_height=\"50dp\"android:background=\"#CC91BD\"android:text=\"@string/querybtntext\"android:textColor=\"#593152\"android:textSize=\"20sp\"android:textStyle=\"bold\" /><TextViewandroid:id=\"@+id/bookNumTextView\"android:layout_width=\"100dp\"android:layout_height=\"wrap_content\"android:layout_marginTop=\"-10dp\"android:layout_marginRight=\"20dp\" /><Buttonandroid:id=\"@+id/nextBtn\"android:layout_width=\"100dp\"android:layout_height=\"50dp\"android:background=\"#CC91BD\"android:text=\"@string/next\"android:textColor=\"#593152\"android:textSize=\"20sp\"android:textStyle=\"bold\" /></LinearLayout></LinearLayout>
tostrings.xml文件代码
<resources><string name=\"app_name\">LibraryDemo</string><string name=\"title\">借书</string><string name=\"nametext\">读者:</string><string name=\"inputname_hint\">请输入名字</string><string name=\"sextext\">性别:</string><string name=\"male\">男</string><string name=\"female\">女</string><string name=\"lendtimetext\">借出时间:</string><string name=\"inputlendtime_hint\">请输入</string><string name=\"returntimetext\">归还时间:</string><string name=\"returntime\">2016.06.30</string><string name=\"hobbytext\">爱好:</string><string name=\"historytext\">历史</string><string name=\"suspensetext\">悬疑</string><string name=\"literaturetext\">文艺</string><string name=\"agetext\">年龄:</string><string name=\"age_18\">18</string><string name=\"age_100\">100</string><string name=\"bookname\">书名</string><string name=\"kind\">类型</string><string name=\"age\">适用年龄</string><string name=\"querybtntext\">查找</string><string name=\"next\">下一个</string></resources>
书本类和用户类的定义
书本类Book
根据要求,书本类属性包括以下属性
- String:书名name,类型kind
- int:适用年龄age,图片的地址pic
- boolean:是否属于历史、悬疑、文艺
public class Book {//属性:书名、类型、适用年龄、图片地址//三个boolean类型:历史、悬疑、文艺private String name;private String kind;private int age;private int pic;boolean his;boolean sus;boolean lit;public Book() {}public Book(String name, String kind, int age, int pic, boolean his, boolean sus, boolean lit) {this.name = name;this.kind = kind;this.age = age;this.pic = pic;this.his = his;this.sus = sus;this.lit = lit;}//getter和setter方法...}
用户类Person
根据要求,书本类属性包括以下属性
- String:姓名name,性别sex
- int:年龄age
- Date:借书时间lendTime
- Book:书本类对象book
public class Person {//属性:姓名、性别、借书时间、书本//年龄默认为20岁private String name;private String sex;private int age = 20;private Date lendTime;private Book book;public Person() {}public Person(String name, String sex, int age, Date lendTime, Book book) {this.name = name;this.sex = sex;this.age = age;this.lendTime = lendTime;this.book = book;}//getter和setter方法...}
用户在UI界面输入的借书时间是String类型,不能通过Person类原始的setLendTime方法直接传参,需要将传进来的字符串进行格式转换
//将输入的时间(String类型)转换为Date类型,格式\"yyyy-MM-dd\"public void setLendTime(String dateString) throws ParseException {this.lendTime = new SimpleDateFormat(\"yyyy-MM-dd\").parse(dateString);}
功能实现
首先确定onCreate方法的实现思路
为了代码的可读性,我把功能实现都封装在了方法体内
- 加载布局文件setContentView()
- 初始化控件findViews()
- 初始化数据initData()
- 为控件添加监听器并实现基本功能setListeners()
@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);//初始化控件findViews();//初始化数据initData();//为控件添加监听器,实现基本功能setListeners();}
添加布局文件的方法在创建工程的时候已经自动生成了,所以就不用另外再写一遍
初始化控件findViews()
在这个方法体实现了获取控件ID的功能以及部分控件设置初始值操作
//初始化控件,获取控件IDprivate void findViews() {mNameEditText = findViewById(R.id.nameEditText);mLendEditText = findViewById(R.id.lendEditText);mSexRadioGroup = findViewById(R.id.sexRadioGroup);mHisCheckBox = findViewById(R.id.hisCheckBox);mSusCheckBox = findViewById(R.id.susCheckBox);mLitCheckBox = findViewById(R.id.litCheckBox);mSeekBar = findViewById(R.id.seekBar);//设置SeekBar的初始值为20mSeekBar.setProgress(20);mAgeTextView = findViewById(R.id.seekBar_ageTextView);//设置SeekBar控件左边的TextView显示的数值与SeekBar当前数值保持一致mAgeTextView.setText(String.valueOf(mSeekBar.getProgress()));mQueryButton = findViewById(R.id.queryBtn);mNextButton = findViewById(R.id.nextBtn);mBookImageView = findViewById(R.id.bookImageView);mBookNumTextView = findViewById(R.id.bookNumTextView);mBookName = findViewById(R.id.bookNameTextView);mBookKind = findViewById(R.id.bookKindTextView);mBookAge = findViewById(R.id.bookAgeTextView);mReturnTime = findViewById(R.id.returnTime);}
这里有个小技巧,在完成声明后选择该行按Ctrl+Alt+F,可以将声明操作提取成私有全局变量
private EditText mNameEditText;private RadioGroup mSexRadioGroup;private CheckBox mHisCheckBox;private CheckBox mSusCheckBox;private CheckBox mLitCheckBox;private SeekBar mSeekBar;private Button mQueryButton;private Button mNextButton;private ImageView mBookImageView;private List<Book> mBooks;private Person mPerson;private List<Book> mBookResult;private boolean mIsHistory;private boolean mIsSuspense;private boolean mIsLiterature;private int mAge;private int mCurrentIndex;private TextView mAgeTextView;private TextView mBookNumTextView;private TextView mBookName;private TextView mBookAge;private TextView mBookKind;private EditText mLendEditText;private TextView mReturnTime;private Date lend = null;private Date borrow = null;
初始化数据initData()
工程不包含数据库方面的技术,这里通过initData方法初始化所有书本对象的信息,并且把它加入到
mBooks
集合中
mBookResult
符合条件的书本集合
borrow
还书时间,这里把时间直接写死了,也可以通过其它方法来获取当前系统的时间
//初始化数据private void initData() {//初始化书本集合mBooks = new ArrayList<Book>();mBooks.add(new Book(\"人生感悟\", \"心灵鸡汤\", 43, R.mipmap.aa, false, false, true));mBooks.add(new Book(\"边城\", \"文学\", 30, R.mipmap.bb, false, false, true));mBooks.add(new Book(\"sapir\", \"传记\", 28, R.mipmap.cc, true, false, true));mBooks.add(new Book(\"光辉岁月\", \"历史\", 50, R.mipmap.dd, true, false, false));mBooks.add(new Book(\"宋词三百首\", \"诗文\", 88, R.mipmap.ee, false, false, true));mBooks.add(new Book(\"中国古代文学\", \"教学纲要\", 42, R.mipmap.ff, false, false, true));mBooks.add(new Book(\"无花果\", \"诗文\", 35, R.mipmap.gg, false, false, true));mBooks.add(new Book(\"古镇记忆\", \"悬疑\", 22, R.mipmap.hh, true, true, false));//始化用户对象mPerson = new Person();//初始化书本查找集合mBookResult = new ArrayList<Book>();//初始化还书时间try {borrow = new SimpleDateFormat(\"yyyy-MM-dd\").parse(\"2016-06-30\");} catch (ParseException e) {e.printStackTrace();}}
添加监听器setListeners()
这一块是整个Demo的核心代码,大部分控件的响应事件都封装在这里
//为控件添加监听器private void setListeners() {
mNameEditText监听器
将用户输入的姓名字符串传给
mPerson
对象的setName方法修改
mPerson
的
name
属性
//nameEditText监听器mNameEditText.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {if (mPerson != null)mPerson.setName(s.toString());}});
传参之前先判断一下是否为空避免崩溃
mLendEditText监听器
将用户输入的时间字符串传给
mPerson
对象的setLendTime方法修改
mPerson
的
lendTime
属性,并将
lendTime
赋值给
this.lend
//lendEditText监听器mLendEditText.addTextChangedListener(new TextWatcher() {@Overridepublic void beforeTextChanged(CharSequence s, int start, int count, int after) {}@Overridepublic void onTextChanged(CharSequence s, int start, int before, int count) {}@Overridepublic void afterTextChanged(Editable s) {if (mPerson != null) {try {mPerson.setLendTime(s.toString());} catch (ParseException e) {e.printStackTrace();}}lend = mPerson.getLendTime();}});
传参时同样要判断对象是否为空
mSexRadioGroup监听器
性别选择的RadioButton放在一个RadioGroup里面,通过监听用户的选择给
mPerson.sex
进行赋值
//RadioGroup监听器mSexRadioGroup.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(RadioGroup group, int checkedId) {switch (checkedId) {case R.id.male:mPerson.setSex(getString(R.string.male));break;case R.id.female:mPerson.setSex(getString(R.string.female));break;}}});
三个CheckBox的监听器
存储用户的阅读喜好
//hisCheckBox监听器mHisCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {mIsHistory = isChecked;}});//susCheckBox监听器mSusCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {mIsSuspense = isChecked;}});//litCheckBox监听器mLitCheckBox.setOnCheckedChangeListener(new CompoundButton.OnCheckedChangeListener() {@Overridepublic void onCheckedChanged(CompoundButton buttonView, boolean isChecked) {mIsLiterature = isChecked;}});
SeekBar监听器
这里只需获取用户滑动结果,并通过
Toast
来显示结果
mAge
用户选择的年龄int类型
mAgeTextView
是位于SeekBar左边的TextView控件,内容与当前选择的年龄一致
//seekBar监听器mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {@Overridepublic void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {}@Overridepublic void onStartTrackingTouch(SeekBar seekBar) {}@Overridepublic void onStopTrackingTouch(SeekBar seekBar) {mAge = seekBar.getProgress();mPerson.setAge(mAge);//SeekBar左边的TextView更新为当前年龄mAgeTextView.setText(String.valueOf(mSeekBar.getProgress()));Toast.makeText(MainActivity.this, \"年龄:\" + mAge, Toast.LENGTH_SHORT).show();}});
mQueryButton监听器
//查找按钮监听器mQueryButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {//格式化显示输入的借书时间mLendEditText20000.setText(new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(lend));//每次查找前初始化图片及文字信息mBookImageView.setImageResource(R.mipmap.f);mBookName.setText(R.string.bookname);mBookKind.setText(R.string.kind);mBookAge.setText(R.string.age);mBookNumTextView.setText(\"\");if (mPerson.getName() == null)Toast.makeText(MainActivity.this, \"姓名不能为空!\", Toast.LENGTH_SHORT).show();else if (mPerson.getLendTime() == null)Toast.makeText(MainActivity.this, \"借书日期不能为空!\", Toast.LENGTH_SHORT).show();else if (mPerson.getSex() == null)Toast.makeText(MainActivity.this, \"请选择性别!\", Toast.LENGTH_SHORT).show();else if (compareDate()) {//判断借出时间是否大于归还时间Toast.makeText(MainActivity.this, \"借书时间晚于还书时间,程序退出!\", Toast.LENGTH_SHORT).show();finish();} elsesearchBook();}});
mNextButton监听器
//下一个按钮监听器mNextButton.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {mCurrentIndex++;if (mCurrentIndex < mBookResult.size()) {mBookImageView.setImageResource(mBookResult.get(mCurrentIndex).getPic());Toast.makeText(MainActivity.this, \"显示:Person[per_name=\" + mPerson.getName()+ \",sex=\" + mPerson.getSex() + \",age=\" + mPerson.getAge()+ \",time=\" + new SimpleDateFormat(\"yyyy-MM-dd HH:mm:ss\").format(lend) + \"]\", Toast.LENGTH_SHORT).show();//ImageView右边显示书籍信息mBookName.setText(mBookResult.get(mCurrentIndex).getName());mBookAge.setText(String.valueOf(mBookResult.get(mCurrentIndex).getAge()));mBookKind.setText(mBookResult.get(mCurrentIndex).getKind());//按钮右边的TextView显示剩余数量mBookNumTextView.setText(\"符合条件的书还剩\" + (mBookResult.size() - mCurrentIndex - 1) + \"本\");} else {Toast.makeText(MainActivity.this, \"没有啦!\", Toast.LENGTH_SHORT).show();}}});
查找书籍方法主体
//查找书籍private void searchBook() {//如果为空,先初始化书籍结果对象if (mBookResult == null)mBookResult = new ArrayList<Book>();//清空结果列表mBookResult.clear();mCurrentIndex = 0;//遍历所有书籍for (int index = 0; index < mBooks.size(); index++) {Book book = mBooks.get(index);//适用年龄要大于设定年龄//符合爱好的选择if (book != null) {if (book.getAge() >= mAge&& ((book.isHis() == true) && (book.isHis() == mIsHistory)|| (book.isLit() == true) && (book.isLit() == mIsLiterature)|| (book.isSus() == true) && (book.isSus() == mIsSuspense))) {mBookResult.add(book);}}}if (mCurrentIndex < mBookResult.size()) {//先显示第一张图片mBookImageView.setImageResource(mBookResult.get(mCurrentIndex).getPic());//ImageView右边显示书籍信息mBookName.setText(mBookResult.get(mCurrentIndex).getName());mBookAge.setText(String.valueOf(mBookResult.get(mCurrentIndex).getAge()));mBookKind.setText(mBookResult.get(mCurrentIndex).getKind());//按钮右边的TextView显示剩余数量mBookNumTextView.setText(\"符合条件的书还剩\" + (mBookResult.size() - 1) + \"本\");}}
日期比较方法主体
//日期比较private boolean compareDate() {//若借书时间晚于还书时间,返回trueif (lend.compareTo(borrow) == 1)return true;elsereturn false;}
IDE:Android Studio 4.0