本文目录
- 总体功能目标:
- 前期功能:
- 后期功能:
- 大致思路:
- 当前效果图:
- 开始编码:
- 词库:
- 选择题:
- 用到的基类、自定义Button、工具类
在使用背单词APP的过程中,我发现我就没专心背单词,而是想着:咦,这功能可以!唉?这个地方好像有点小BUG!这里为啥不加点这个功能?那里为啥不加点那个功能?然后我就点开了我的AndroidStudio,开始了接来下的编码之旅!(本文持续更新,感兴趣的小伙伴可收藏一波)
项目地址(GitHub):https://github.com/YJX666666/MyDictionary
总体功能目标:
前期功能:
添加单词:能够添加单词
词库管理:能显示词库所有单词、能删除以及修改单词
选择模式:两种模式(中 - 英 & 英 - 中),选项中有一个正确答案以及三个非正确答案,选择正确和不正确都有相应提示
填空模式:两种模式(中 - 英 & 英 - 中),填写正确和不正确都有相应提示
后期功能:
词库选择:软件内自带几种常用的词库,如四六级等等,选择后添加进当前词库
背诵记录:可以查看单词背诵情况,如:单词出现次数、正确次数、错误次数
智能化:通过背诵记录来智能筛选背诵的单词,如:更多地出现正确率低的单词以加深记忆
大致思路:
利用数据库来保存单词,每次添加单词就直接添加进数据库,选择题是获取四组数据,然后选一组作为当前的主角(当前考核的单词),其余三组作为非正确答案放在按钮上,填空题则比较简单,随机选取一组数据,然后给出单词(或翻译),让你在输入框中填写答案。后期功能思路暂时没有考虑,先把前期功能做完!
当前效果图:
开始编码:
词库:
先写一个SQWordsHelps继承自SQLiteOpenHelper,这里定义两个数据(WORD 和 CHINESE)
public class SQWordsHelper extends SQLiteOpenHelper {
public static final String WORD = "word";
public static final String DB_NAME = WORD + "s.db";
public static final String TABLE_NAME = WORD + "s";
public static final String CHINESE = "chinese";
public SQWordsHelper(Context context) {
super(context, DB_NAME, null, 1);
}
@Override
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table " + TABLE_NAME + "(" + WORD + " text," + CHINESE + " text)");
}
@Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
}
}
然后是添加数据的功能,也就是数据库中的 增
XML,Button我用的自己自定义的Button(文末符代码)
<?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:gravity="center" android:orientation="vertical">
<EditText android:id="@+id/edit_english" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:background="@drawable/edit_stroke" android:gravity="center" android:hint="@string/str_english" android:padding="10dp" android:singleLine="true" android:textSize="22sp" />
<EditText android:id="@+id/edit_chinese" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="20sp" android:layout_marginRight="30dp" android:background="@drawable/edit_stroke" android:gravity="center" android:hint="@string/str_chinese" android:padding="10dp" android:singleLine="true" android:textSize="22sp" />
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_add" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="30dp" android:layout_marginTop="20sp" android:layout_marginRight="30dp" android:text="@string/str_addwords" />
</LinearLayout>
Java,BaseActivity是我写的基类(文末符代码)
点击按钮后进行判断,如果两个输入框中有空的则无反应(可以写一个提示),都不为空则调用插入数据的方法(initSQLiteData())
补充一个小知识点:数据库的 .insert()
方法是有返回值的,当返回 -1 时则为插入数据失败,返回其他则为插入数据成功(返回值是新插入数据所在的行数),这样我们就可以通过返回值来判断并提示用户插入结果
public class AddWordsActivity extends BaseActivity {
private android.widget.EditText mEditEnglish;
private android.widget.EditText mEditChinese;
private android.widget.Button mBtnAdd;
SQWordsHelper mSQHelper;
SQLiteDatabase mSQLiteDatabase;
ContentValues mContentValues;
@Override
protected void initData() {
mSQHelper = new SQWordsHelper(mContext);
mSQLiteDatabase = mSQHelper.getWritableDatabase();
mBtnAdd.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String english = mEditEnglish.getText().toString();
String chinese = mEditChinese.getText().toString();
if (!TextUtils.isEmpty(english) && !TextUtils.isEmpty(chinese)) {
initSQLiteData(english, chinese);
}
}
});
}
private void initSQLiteData(String english, String chinese) {
mContentValues = new ContentValues();
mContentValues.put(SQWordsHelper.WORD, english);
mContentValues.put(SQWordsHelper.CHINESE, chinese);
if (mSQLiteDatabase.insert(SQWordsHelper.TABLE_NAME, null, mContentValues) == -1) {
Toast.makeText(mContext, "添加失败!", Toast.LENGTH_SHORT).show();
} else {
Toast.makeText(mContext, "添加成功!", Toast.LENGTH_SHORT).show();
mEditEnglish.setText("");
mEditChinese.setText("");
}
}
@Override
protected int initLayout() {
return R.layout.addwords;
}
@Override
protected void initView() {
mEditEnglish = findViewById(R.id.edit_english);
mEditChinese = findViewById(R.id.edit_chinese);
mBtnAdd = findViewById(R.id.btn_add);
}
}
选择题:
主体是很简单的一个TextView加上四个Button的布局,然后在按钮的右下角放了一个小一点的Buton,用来获取下一个单词(当然也可以做成选完直接换的那种,不过那种感觉不如这种好),最下面是一个 “掌握了单词” 的TextView,有时候背单词遇到那种已经背的特别熟的单词,就可以通过这种方式直接在背单词的时候删掉,而不是去词库删。
<?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:gravity="center" android:orientation="vertical">
<LinearLayout android:layout_width="wrap_content" android:layout_height="0dp" android:layout_weight="1" />
<TextView android:id="@+id/txv_word" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center" android:textSize="26sp" android:textStyle="bold" />
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_a" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="80dp" android:layout_marginTop="50dp" android:layout_marginRight="80dp" />
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_b" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="80dp" android:layout_marginTop="10dp" android:layout_marginRight="80dp" />
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_c" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="80dp" android:layout_marginTop="10dp" android:layout_marginRight="80dp" />
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_d" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginLeft="80dp" android:layout_marginTop="10dp" android:layout_marginRight="80dp" />
<LinearLayout android:layout_width="match_parent" android:layout_height="0dp" android:layout_marginTop="20sp" android:layout_weight="1" android:orientation="vertical">
<com.yjx.androidword.MyView.MyFirstButton android:id="@+id/btn_next" android:layout_width="100dp" android:layout_height="35dp" android:layout_gravity="right" android:layout_marginTop="10dp" android:layout_marginEnd="10dp" android:text="@string/str_next" android:textSize="12sp" />
</LinearLayout>
<TextView android:id="@+id/txv_grasp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="30dp" android:shadowColor="@color/colorShadowBlack" android:shadowDx="3" android:shadowDy="3" android:shadowRadius="6" android:text="@string/str_grasp" />
</LinearLayout>
Java,后台代码就稍微多了起来,主要代码功能是:通过工具类获取四组数据然后传到TextView和Button上,然后就是判断当前选项是否正确,以及选择正确和不正确时,对按钮进行背景色的替换(选对变绿,选错变红),以及点击 “下一个” 按钮后,所有按钮重置为初始状态并重新获取数据。
public class ChooseActivity extends BaseActivity implements View.OnClickListener {
private android.widget.TextView mTxvWord;
private android.widget.Button mBtnA;
private android.widget.Button mBtnB;
private android.widget.Button mBtnC;
private android.widget.Button mBtnD;
private String mString_English = "";
private String mString_Chinese = "";
private Random mRandom = new Random();
private android.widget.TextView mTxvGrasp;
private SQWordsHelper mSQWordsHelper;
private SQLiteDatabase mSQLiteDatabase;
private TextView mTxvEnglish;
private TextView mTxvChinese;
private TextView mTxvDel;
private TextView mTxvModify;
private List<WordsBean> mListWords = new ArrayList<>();
private Button mBtnNext;
@Override
protected void initData() {
mBtnA.setOnClickListener(this);
mBtnB.setOnClickListener(this);
mBtnC.setOnClickListener(this);
mBtnD.setOnClickListener(this);
mBtnNext.setOnClickListener(this);
mTxvGrasp.setOnClickListener(this);
mSQWordsHelper = new SQWordsHelper(mContext);
mSQLiteDatabase = mSQWordsHelper.getWritableDatabase();
mBtnNext.setVisibility(View.GONE);
//获取需要测试的单词和翻译
setAnswer();
}
private void setAnswer() {
//获取四组数据
mListWords = WordsUtils.get(mContext);
//需要测试的组赋值
mString_English = mListWords.get(0).getEnglish();
mString_Chinese = mListWords.get(0).getChinses();
//单词发送到TextView上
mTxvWord.setText(mString_English);
//随机选取一个按钮放中文答案,其他按钮放上获取的随机非正确答案
switch (mRandom.nextInt(4) % (4) + 1) {
case 1:
mBtnA.setText(mString_Chinese);
mBtnB.setText(mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getChinses());
break;
case 2:
mBtnB.setText(mString_Chinese);
mBtnA.setText(mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getChinses());
break;
case 3:
mBtnC.setText(mString_Chinese);
mBtnA.setText(mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getChinses());
break;
case 4:
mBtnD.setText(mString_Chinese);
mBtnA.setText(mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getChinses());
mBtnC.setText(mListWords.get(3).getChinses());
break;
}
}
//重置按钮
private void reSet() {
mBtnA.setBackground(getResources().getDrawable(R.drawable.btn_background));
mBtnB.setBackground(getResources().getDrawable(R.drawable.btn_background));
mBtnC.setBackground(getResources().getDrawable(R.drawable.btn_background));
mBtnD.setBackground(getResources().getDrawable(R.drawable.btn_background));
mBtnA.setEnabled(true);
mBtnB.setEnabled(true);
mBtnC.setEnabled(true);
mBtnD.setEnabled(true);
}
//选择判断
@SuppressLint("SetTextI18n")
private void getJudg(Button btn, String str_btn) {
if (str_btn.equals(mString_Chinese)) {
//选择正确
btn.setBackground(getResources().getDrawable(R.drawable.btn_green));
if (btn == mBtnA) {
mBtnB.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn == mBtnB) {
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn == mBtnC) {
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn == mBtnD) {
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnC.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
}
} else {
//选择错误
btn.setBackground(getResources().getDrawable(R.drawable.btn_red));
if (btn != mBtnA && mBtnA.getText().toString().equals(mString_Chinese)) {
mBtnA.setBackground(getResources().getDrawable(R.drawable.btn_green2));
mBtnB.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn != mBtnB && mBtnB.getText().toString().equals(mString_Chinese)) {
mBtnB.setBackground(getResources().getDrawable(R.drawable.btn_green2));
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnC.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn != mBtnC && mBtnC.getText().toString().equals(mString_Chinese)) {
mBtnC.setBackground(getResources().getDrawable(R.drawable.btn_green2));
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnD.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
} else if (btn != mBtnD && mBtnD.getText().toString().equals(mString_Chinese)) {
mBtnD.setBackground(getResources().getDrawable(R.drawable.btn_green2));
mBtnA.setText(mListWords.get(1).getEnglish() + " : " + mListWords.get(1).getChinses());
mBtnB.setText(mListWords.get(2).getEnglish() + " : " + mListWords.get(2).getChinses());
mBtnC.setText(mListWords.get(3).getEnglish() + " : " + mListWords.get(3).getChinses());
}
}
//选择完以后设置按钮不可点击
mBtnA.setEnabled(false);
mBtnB.setEnabled(false);
mBtnC.setEnabled(false);
mBtnD.setEnabled(false);
//选择完以后把右下角 下一个 按钮显示出来
mBtnNext.setVisibility(View.VISIBLE);
}
@Override
protected int initLayout() {
return R.layout.layout_choose;
}
@Override
protected void initView() {
mTxvWord = findViewById(R.id.txv_word);
mBtnA = findViewById(R.id.btn_a);
mBtnB = findViewById(R.id.btn_b);
mBtnC = findViewById(R.id.btn_c);
mBtnD = findViewById(R.id.btn_d);
mTxvGrasp = findViewById(R.id.txv_grasp);
mBtnNext = findViewById(R.id.btn_next);
}
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.btn_a:
getJudg(mBtnA, mBtnA.getText().toString());
break;
case R.id.btn_b:
getJudg(mBtnB, mBtnB.getText().toString());
break;
case R.id.btn_c:
getJudg(mBtnC, mBtnC.getText().toString());
break;
case R.id.btn_d:
getJudg(mBtnD, mBtnD.getText().toString());
break;
case R.id.btn_next://下一个
reSet();
setAnswer();
mBtnNext.setVisibility(View.GONE);
break;
case R.id.txv_grasp:
View view = LayoutInflater.from(mContext).inflate(R.layout.dialog_words_menu, null);
mTxvEnglish = view.findViewById(R.id.txv_english);
mTxvChinese = view.findViewById(R.id.txv_chinese);
mTxvDel = view.findViewById(R.id.txv_del);
mTxvModify = view.findViewById(R.id.txv_modify);
mTxvEnglish.setText("English:" + mString_English);
mTxvChinese.setText("中文:" + mString_Chinese);
mTxvDel.setText("掌握(删除)");
mTxvModify.setText("取消");
final Dialog dialog = DialogUtils.show(mContext, view);
mTxvDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
removeData(mString_English);
reSet();
dialog.dismiss();
}
});
mTxvModify.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
dialog.dismiss();
}
});
break;
}
}
private void removeData(String str_del) {
//数据库同步删除
String clause = SQWordsHelper.WORD + "=?";
mSQLiteDatabase.delete(SQWordsHelper.TABLE_NAME, clause, new String[]{str_del});
}
}
到这就算完成了:添加单词、词库管理、选择模式了!逻辑比较简单,然后本人也是初学者,很多代码写得比较冗杂,有很多可以优化的地方,这些都等前期功能全都实现了再进行一波优化!
用到的基类、自定义Button、工具类
基类BaseActivity
public abstract class BaseActivity extends AppCompatActivity {
protected Context mContext;
@Override
protected void onCreate(Bundle savedInstanceState) {
initWindow();
super.onCreate(savedInstanceState);
mContext = BaseActivity.this;
setContentView(initLayout());
//控件声明
initView();
//数据
initData();
}
protected abstract void initData();
protected void initWindow() {
}
protected abstract int initLayout();
protected abstract void initView();
}
自定义Button,MyFirstButton
@SuppressLint("AppCompatCustomView")
public class MyFirstButton extends Button {
//字体阴影
private int mShadowRadius =6;
private int mShadowDx = 3;
private int mShadowDy= 3;
private int mShadowColor= getResources().getColor(R.color.colorShadowBlack);
//字体样式
private Typeface mTypeface= Typeface.DEFAULT;
private int mStyle= Typeface.BOLD;
//背景
private Drawable mBackground= getResources().getDrawable(R.drawable.btn_background);
//字体颜色
private int mTextColor= getResources().getColor(R.color.colorWhite);
private void set() {
//阴影
super.setShadowLayer(mShadowRadius, mShadowDx, mShadowDy, mShadowColor);
//字体样式
super.setTypeface(mTypeface, mStyle);
//背景
super.setBackground(mBackground);
//字体颜色
super.setTextColor(mTextColor);
}
public MyFirstButton(Context context) {
super(context);
set();
}
public MyFirstButton(Context context, AttributeSet attrs) {
super(context, attrs);
set();
}
public MyFirstButton(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
set();
}
}
获取单词的工具类,这里的功能是随机获取词库中不相同的四组数据返回,实现原理是:首先获取词库所有的数据,然后通过获取四个不相同的随机数,最后用这四个随机数作为下标来获取数组中的四组数据,就相当于是随机获取了数组中的四组数据了!
public class WordsUtils {
private static List<WordsBean> sList;
private static List<WordsBean> sList_Return;
private static SQWordsHelper sMSQHelper;
private static Cursor sCursor;
private static SQLiteDatabase sSQLiteDatabase;
private static WordsBean sGetWordBean;
private static Random sRandom = new Random();
private static Set<Integer> sSetReturn;
private static int sI;
private static Object[] sArray;
public static List<WordsBean> get(Context context) {
sList = new ArrayList<>();
sSetReturn = new HashSet<>();
sList_Return = new ArrayList<>();
sMSQHelper = new SQWordsHelper(context);
sSQLiteDatabase = sMSQHelper.getWritableDatabase();
sCursor = sSQLiteDatabase.query(SQWordsHelper.TABLE_NAME, null, null, null, null, null, null);
//获取总词库
while (sCursor.moveToNext()) {
sGetWordBean = new WordsBean();
String english = sCursor.getString(0);
String chinese = sCursor.getString(1);
sGetWordBean.setEnglish(english);
sGetWordBean.setChinses(chinese);
sList.add(sGetWordBean);
}
sSetReturn.clear();
//四个随机数
while (sSetReturn.size() <= 4) {
sI = sRandom.nextInt(sList.size()) % (sList.size());
sSetReturn.add(sI);
}
//随机的四组数据传入返回的数组中
sArray = sSetReturn.toArray();
for (int i = 0; i < sArray.length; i++) {
sGetWordBean = new WordsBean();
sGetWordBean.setEnglish(sList.get((Integer) sArray[i]).getEnglish());
sGetWordBean.setChinses(sList.get((Integer) sArray[i]).getChinses());
sList_Return.add(sGetWordBean);
}
return sList_Return;
}
}
对话框工具类
public class DialogUtils {
//自定义View对话框
public static Dialog show(Context context, View view) {
AlertDialog.Builder builder = new AlertDialog.Builder(context)
.setView(view)
.setCancelable(true);
Dialog dialog = builder.show();
dialog.getWindow().getDecorView().setBackground(null);
return dialog;
}
}
BUG求助:随机获取的数据会莫名固定那么几个,暂未查明原因,希望有大佬评论区或者私聊帮助一下
同样欢迎小伙们一起研究探讨!
下一步将进阶填空题!
本文持续更新(感兴趣可以收藏一波)…