1.功能介紹
關鍵技術:SQLite,fragment,ViewFlipper,OnTouchListener
(1)搜尋:在搜尋框中輸入關鍵詞,搜尋包含該關鍵詞的題目,并可檢視題目詳情。
(2)題庫:按内容和來源兩種分類的題庫,可選擇題庫種的題目進行測試或者練習。其中練習沒有計時,沒有計分,但能儲存目前做題進度;測試計時且計分,最後會顯示成績
(3)錯題:按内容和來源兩種分類的錯題集,可進行練習
(4)收藏:按内容和來源兩種分類的收藏,可進行練習
(5)我的記錄:記錄每次測試的用時和分數
2.搜尋功能
【思路】通過關鍵詞,先從SQLite中擷取資料cursor,然後在ListView中加載,并設定OnItemClickListener,跳轉到對應的題目詳情。
【注意】
(1)搜尋結果清單,需要設定limit限制清單數量和更多或沒有結果的提示資訊,以免一次性加載,導緻記憶體溢出或者加載緩慢。
(2)查詢關鍵詞的語句是(冒号和空格一定要仔細檢查)
"select _id,que from que where que like '%"+text +"%' or choiceA like '%"+text+"%' or choiceB like'%"+text +"%' or choiceC like'%"+text+"%' or choiceD ike'%"+text+"%' limit "+limit"
activity_search.xml 搜尋界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.lidan.xiao.danquestion.activity.SearchActivity">
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar1"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.PopupOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<EditText
android:id="@+id/sv"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:textColor="@color/white"
android:layout_weight="1"/>
<ImageView
android:id="@+id/img_search"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/search"
android:padding="8dp"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.lidan.xiao.danquestion.view.MyListView
android:id="@+id/lv_search"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tv_info"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColor="@color/gray"
android:padding="8dp"
android:gravity="center"
android:background="@drawable/bt1"
android:textSize="16dp"/>
</LinearLayout>
</ScrollView>
</LinearLayout>
listitem1.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="wrap_content"
android:orientation="horizontal"
android:background="@android:drawable/picture_frame">
<TextView
android:id="@+id/tv_item2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:ellipsize="end"
android:textSize="14sp"/>
</LinearLayout>
MyListView .java
//自定義ListView防止在ScrollView中不能正常顯示
public class MyListView extends ListView {
public MyListView(Context context) {
super(context);
}
public MyListView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyListView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public MyListView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,
MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
}
}
public class SearchActivity extends AppCompatActivity implements View.OnClickListener {
private EditText sv;
private MyListView lv;
private TextView tv;
private ImageView submit;
private boolean isLv=false;
private int num=0,limit=10;
private Cursor cursor;
private SimpleCursorAdapter adapter;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_search);
//ActionBar工具欄設定
Toolbar toolbar = findViewById(R.id.toolbar1);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
sv=findViewById(R.id.sv);
submit=findViewById(R.id.img_search);
tv=findViewById(R.id.tv_info);
lv=findViewById(R.id.lv_search);
submit.setOnClickListener(this);
}
@Override
public void onClick(View v) {
String text=sv.getText().toString();
if(!text.isEmpty()){
searchResult(text);
}else {
Toast.makeText(this,"請輸入查詢内容",Toast.LENGTH_LONG).show();
}
}
//查詢結果加載
private void searchResult(final String text) {
cursor = ToolHelper.loadDB(this,"select _id,que from que where que like '%"+text
+"%' or choiceA like '%"+text+"%' or choiceB like'%"+text
+"%' or choiceC like'%"+text+"%' or choiceD like'%"+text+"%' limit "+limit);
num=cursor.getCount();
if(num>0) {
if(!isLv) {//如果lv未建立
adapter = new SimpleCursorAdapter(this, R.layout.listitem1, cursor,
new String[]{"que"}, new int[]{R.id.tv_item2},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
cursor.moveToPosition(position);
int select = cursor.getInt(cursor.getColumnIndex("_id"));
Intent intent = new Intent(SearchActivity.this, DetailActivity.class);
intent.putExtra("qid", select);
startActivity(intent);
}
});
isLv=true;
}else {//如果lv已經建立,資料改變則重新加載lv
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
}
resultTv(text);
}else {
limit=10;
if(isLv){
adapter.changeCursor(cursor);
adapter.notifyDataSetChanged();
isLv=false;
}
tv.setVisibility(View.VISIBLE);
tv.setText("無查詢結果");
}
}
//提示資訊TextView設定
private void resultTv(final String text) {
if(num<limit) {//如果查詢結果數小于限制數
tv.setVisibility(View.GONE);
limit=10;
}else if(num>=limit){//如果查詢結果數多于限制數
tv.setText("更多查詢資料");
tv.setVisibility(View.VISIBLE);
tv.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
limit=limit+10;
searchResult(text);
//Toast.makeText(SearchActivity.this,"limit="+String.valueOf(limit),Toast.LENGTH_SHORT).show();
}
});
}
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if(item.getItemId()==android.R.id.home){//傳回
finish();
}
return super.onOptionsItemSelected(item);
}
}
activity_detail.xml 詳情界面
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context="com.lidan.xiao.danquestion.activity.DetailActivity">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="@layout/layout_top1"/>
<TextView
android:id="@+id/tv_que"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="#000000"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_choice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/colorPrimary" />
<TextView
android:id="@+id/tv_answer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/colorAccent" />
<TextView
android:id="@+id/tv_source"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/gray"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_detail"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:textColor="@color/gray"
android:textSize="14sp" />
</LinearLayout>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_collect"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end"
android:layout_marginRight="8dp"
android:layout_marginTop="180dp" />
</FrameLayout>
public class DetailActivity extends AppCompatActivity {
private TextView tv_que, tv_choice, tv_answer, tv_source, tv_detail;
private FloatingActionButton fabcollect;
private int qid;
private boolean tag = false;
private String kind, type, choice, que, answer, source, detail;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
//ActionBar工具欄設定
Toolbar toolbar = findViewById(R.id.toolbar1);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
tv_que = findViewById(R.id.tv_que);
tv_choice = findViewById(R.id.tv_choice);
tv_answer = findViewById(R.id.tv_answer);
tv_source = findViewById(R.id.tv_source);
tv_detail = findViewById(R.id.tv_detail);
fabcollect = findViewById(R.id.fab_collect);
Intent intent = getIntent();
qid = intent.getIntExtra("qid", 0);
if (qid > 0) {
loadData();
initData();
initCollect();
}
}
private void initCollect() {
final Cursor cursor = ToolHelper.loadDB(this, "select qid from collection where qid=" + qid);
if (cursor.getCount() > 0) {
tag = true;
fabcollect.setImageResource(R.drawable.star_on);
} else {
tag = false;
fabcollect.setImageResource(R.drawable.star1);
}
fabcollect.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (tag) {
fabcollect.setImageResource(R.drawable.star1);
Toast.makeText(DetailActivity.this, "取消收藏", Toast.LENGTH_SHORT).show();
ToolHelper.excuteDB(DetailActivity.this, "delete from collection where qid=" + qid);
} else {
fabcollect.setImageResource(R.drawable.star_on);
Toast.makeText(DetailActivity.this, "成功收藏", Toast.LENGTH_SHORT).show();
ToolHelper.excuteDB(DetailActivity.this, "insert into collection (_id,qid) values (" + (Math.random()*10000) + "," + qid + ")");
}
}
});
}
private void loadData() {
Cursor cursor = ToolHelper.loadDB(this, "select * from que where _id=" + qid);
cursor.moveToFirst();
kind = cursor.getString(cursor.getColumnIndex("kind"));
String choiceA = "A."+cursor.getString(cursor.getColumnIndex("choiceA"));
String choiceB = "B."+cursor.getString(cursor.getColumnIndex("choiceB"));
String choiceC = "C."+cursor.getString(cursor.getColumnIndex("choiceC"));
String choiceD = "D."+cursor.getString(cursor.getColumnIndex("choiceD"));
StringBuffer sb = new StringBuffer();
if (choiceA != "null") {
sb.append(choiceA + "\n");
}
if (choiceB != "null") {
sb.append(choiceB + "\n");
}
if (choiceC != "null") {
sb.append(choiceC + "\n");
}
if (choiceD != "null") {
sb.append(choiceD + "\n");
}
choice = sb.toString();
que = cursor.getString(cursor.getColumnIndex("que"));
type = cursor.getString(cursor.getColumnIndex("type"));
answer = cursor.getString(cursor.getColumnIndex("answer"));
source = cursor.getString(cursor.getColumnIndex("source"));
detail = cursor.getString(cursor.getColumnIndex("detail"));
}
private void initData() {
setTitle(kind);
tv_que.setText("(" + type + ")" + que);
tv_choice.setText(choice);
tv_answer.setText("【答案】" + answer);
tv_source.setText("【來源】" + source);
tv_detail.setText("【解析】" + detail);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
if (item.getItemId() == android.R.id.home)
finish();
return super.onOptionsItemSelected(item);
}
}
3.測試和練習功能
測試功能中有計時,滑動切換試題,題号選擇卡,收藏,錯對判斷和儲存錯題,測試結束後會儲存考試成績。
練習功能中有滑動切換試題,題号選擇卡,收藏,儲存上次進度,錯對判斷和儲存錯題。
【滑動切換題目思路】使用AdapterViewFlipper和OnToucherListener實作,首先使用List來存儲每個題目view,然後使用BaseAdapter加載到AdapterViewFlipper中,并通過AdapterViewFlipper的OnToucherListener來實作滑動切換題目的指針,切換題目view。
【題号卡思路】使用GridView來顯示所有題目号,并标志已答題目,點選題号是傳回答題界面結果,并将跳轉到選擇題目view,其中,viewFlipper不能直接設定目前view的Id來實作跳轉,是以可以通過擷取目前的題目view的Id,與選擇題号相比較,用showPrevious和showNext來實作。
【錯對判斷思路】當點選送出目前題目的按鈕時。先擷取checkbox是否被選中,用StringBuffer來拼接自己答案,并存儲自己選擇的答案到List中來标志為已答題目,然後通過與參考答案對比,看是否加分,如果正确直接跳轉到下一題,否則顯示正确答案和解析,并存儲錯題。最後一題完成後會直接顯示成績和考試用時,并儲存測試記錄。
【注意】
(1)選擇測試和練習的題目需顯示點選選擇後的那項需改變一下,提醒已經選擇了該項。
(2)儲存錯題前一定要檢查此題是否已經存在,以免重複。
(3)收藏功能,判斷目前題目是否被收藏,并顯示,如果未收藏則可以點選按鈕,并收藏成功。
(3)儲存上次練習進度,直接通過sharedPreference儲存目前練習的指針位置。
fragment_question.xml 題庫/錯題/收藏界面
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@android:id/tabhost"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp">
<TextView
android:id="@+id/top_source"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"/>
<TextView
android:id="@+id/top_kind"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"/>
</LinearLayout>
<ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:id="@+id/tab1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.lidan.xiao.danquestion.view.MyListView
android:id="@+id/lv_que"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="@+id/tv_info1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="8dp" />
</LinearLayout>
</ScrollView>
</LinearLayout>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="8dp"
android:layout_gravity="end|bottom"
android:orientation="vertical">
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_prac"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/test"/>
<android.support.design.widget.FloatingActionButton
android:id="@+id/fab_test"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:src="@drawable/exam"/>
</LinearLayout>
</FrameLayout>
@SuppressLint("ValidFragment")
public class QuestionFragment extends Fragment implements View.OnClickListener {
private int tab;
private boolean tag = false;
private View rootView,itemView=null;
private ListView lv;
private String table,content;
public static String field,value;
private TextView tv1, tv2, info;
private SimpleCursorAdapter adapter;
private Cursor cursor;
private FloatingActionButton fabtest,fabprac;
@SuppressLint("ValidFragment")
public QuestionFragment(int tab) {
this.tab = tab;
}
@Nullable
@Override
public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_question, container, false);
tv1 = rootView.findViewById(R.id.top_source);
tv2 = rootView.findViewById(R.id.top_kind);
info = rootView.findViewById(R.id.tv_info1);
info.setText("無内容");
tv1.setText("來源");
tv2.setText("分類");
tv1.setOnClickListener(this);
tv2.setOnClickListener(this);
lv = rootView.findViewById(R.id.lv_que);
fabtest = rootView.findViewById(R.id.fab_test);
fabtest.setOnClickListener(this);
fabprac=rootView.findViewById(R.id.fab_prac);
fabprac.setOnClickListener(this);
loadData();
tab1();
return rootView;
}
//加載分類題庫
private void tab2() {
tv1.setTextColor(getResources().getColor(R.color.gray));
tv2.setTextColor(getResources().getColor(R.color.colorAccent));
queList("kind");
}
//加載來源題庫
private void tab1() {
tv1.setTextColor(getResources().getColor(R.color.colorAccent));
tv2.setTextColor(getResources().getColor(R.color.gray));
queList("source");
}
private void loadData() {
switch (tab) {
case MyTag.QUE://題庫
table = "que";
content="題庫";
break;
case MyTag.COLLECT://收藏
table = "collection ,que where collection.qid=que._id ";
fabtest.setVisibility(View.GONE);
content="收藏";
break;
case MyTag.WRONG://錯題
table = "wrong,que where wrong.qid=que._id ";
fabtest.setVisibility(View.GONE);
content="錯題";
break;
}
}
//加載内容到清單
private void queList(final String type) {
cursor = ToolHelper.loadDB(getActivity(), "select que._id, que." + type + ",count(que._id) as num from " + table + " group by que." + type+" order by source desc");
if (cursor.getCount() > 0) {
if (!tag) {
adapter = new SimpleCursorAdapter(getActivity(), R.layout.listitem, cursor,
new String[]{type, "num"}, new int[]{R.id.tv_item, R.id.tv_item1},
CursorAdapter.FLAG_REGISTER_CONTENT_OBSERVER);
lv.setAdapter(adapter);
lv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
TextView tv=view.findViewById(R.id.tv_item);
if(itemView!=null) {
TextView tv1=itemView.findViewById(R.id.tv_item);
tv1.setTextColor(getResources().getColor(R.color.colorPrimaryDark));
}
tv.setTextColor(getResources().getColor(R.color.colorAccent));
itemView=view;
field =type;
value=cursor.getString(cursor.getColumnIndex(type));
}
});
info.setVisibility(View.GONE);
} else {
adapter.notify();
}
} else {
info.setVisibility(View.VISIBLE);
info.setText("無記錄");
}
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.fab_test:
if(itemView!=null)
askDialog("測試:",2);
else
Toast.makeText(getActivity(),"請選擇題目集",Toast.LENGTH_SHORT).show();
break;
case R.id.fab_prac:
if(itemView!=null)
askDialog("練習:",1);
else
Toast.makeText(getActivity(),"請選擇題目集",Toast.LENGTH_SHORT).show();
break;
case R.id.top_source:
tab1();
break;
case R.id.top_kind:
tab2();
break;
}
}
private void askDialog(String str,final int c) {
AlertDialog.Builder builder=new AlertDialog.Builder(getActivity());
builder.setMessage(str+"("+content+")"+value+"?");
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
Intent intent;
if(c==2) {
intent = new Intent(getActivity(), QuestionActivity.class);
}else {
intent = new Intent(getActivity(), PracticeActivity.class);
}
intent.putExtra("tab",tab);
startActivity(intent);
}
});
builder.setNegativeButton("取消",null);
builder.show();
}
}
activity_question.xml 題庫測試界面
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fitsSystemWindows="true"
tools:context=".activity.QuestionActivity"
android:orientation="vertical">
<android.support.design.widget.AppBarLayout
android:id="@+id/app_bar"
android:layout_width="match_parent"
android:layout_height="56dp"
android:fitsSystemWindows="true"
android:theme="@style/AppTheme.AppBarOverlay">
<android.support.v7.widget.Toolbar
android:id="@+id/toolbar_que"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:layout_collapseMode="pin"
app:popupTheme="@style/AppTheme.PopupOverlay">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:gravity="center">
<ImageView
android:id="@+id/img_pre"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/pre"/>
<ImageView
android:id="@+id/img_card"
android:layout_width="32dp"
android:layout_height="32dp"
android:layout_margin="8dp"
android:src="@drawable/quecard"/>
<Chronometer
android:id="@+id/mytime"
android:layout_width="80dp"
android:layout_height="wrap_content"
android:gravity="center"
android:textColor="@color/white" />
<ImageView
android:id="@+id/img_collect"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/star1"
android:layout_margin="8dp"/>
<ImageView
android:id="@+id/img_next"
android:layout_width="32dp"
android:layout_height="32dp"
android:src="@drawable/next"/>
</LinearLayout>
</android.support.v7.widget.Toolbar>
</android.support.design.widget.AppBarLayout>
<include layout="@layout/que_content"/>
</LinearLayout>
queitem.xml題目view
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/tv_que1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp" />
<CheckBox
android:id="@+id/cb_choice1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@drawable/cb"
android:padding="8dp"
android:textColor="@color/colorPrimary" />
<CheckBox
android:id="@+id/cb_choice2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@drawable/cb"
android:padding="8dp"
android:textColor="@color/colorPrimary" />
<CheckBox
android:id="@+id/cb_choice3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@drawable/cb"
android:padding="8dp"
android:textColor="@color/colorPrimary" />
<CheckBox
android:id="@+id/cb_choice4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:button="@drawable/cb"
android:padding="8dp"
android:textColor="@color/colorPrimary" />
<TextView
android:id="@+id/tv_you"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/colorAccent" />
<TextView
android:id="@+id/tv_answer1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/colorAccent" />
<TextView
android:id="@+id/tv_detail1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:textColor="@color/gray" />
</LinearLayout>
</ScrollView>
//答題Activity
public class QuestionActivity extends AppCompatActivity implements View.OnClickListener {
private int tab;
private String table,content;
private TextView tvTitle, tvScore;
private Chronometer chronometer;
private Cursor cursor;
private boolean isCollect=false,isFirst=false;
private int num;
private int score = 0,index=0;
public static List<String> anList;
private String source;
private String qid, type, que, A, B, C, D, answer, detail;
private ImageView imgPre, imgNext;
private AdapterViewFlipper vf;
private BaseAdapter adapter;
private ProgressBar pb;
private View root;
private TextView tvQue, tvDetail, tvAns, tvYou;
private CheckBox cb1, cb2, cb3, cb4;
private ImageView imgCollect,imgCard;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_question);
//ActionBar工具欄設定
Toolbar toolbar = findViewById(R.id.toolbar_que);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent intent=getIntent();
tab=intent.getIntExtra("tab",1);
initTable();
initView();
}
private void initTable() {
switch (tab) {
case MyTag.QUE://題庫
table = "que";
content="題庫";
break;
case MyTag.COLLECT://收藏
table = "collection ,que where collection.qid=que._id ";
content="收藏";
break;
case MyTag.WRONG://錯題
table = "wrong,que where wrong.qid=que._id ";
content="錯題";
break;
}
}
@SuppressLint("SetTextI18n")
private void initView() {
//初始化收藏按鈕
imgCollect =findViewById(R.id.img_collect);
imgCollect.setOnClickListener(this);
//初始化答題卡按鈕
imgCard=findViewById(R.id.img_card);
imgCard.setOnClickListener(this);
//初始化計時器
chronometer = findViewById(R.id.mytime);
chronometer.setBase(SystemClock.elapsedRealtime());
chronometer.start();
chronometer.setOnChronometerTickListener(new Chronometer.OnChronometerTickListener() {
@Override
public void onChronometerTick(Chronometer chronometer) {
if (SystemClock.elapsedRealtime() - chronometer.getBase() == 1.5 * 360 * 1000) {
Toast.makeText(QuestionActivity.this, "考試時間到", Toast.LENGTH_LONG).show();
saveExam();
}
}
});
//擷取題目集關鍵字
String field = QuestionFragment.field;
String value = QuestionFragment.value;
source = value;
//設定标題
tvTitle = findViewById(R.id.tv_title);
tvTitle.setText(source);
//擷取SQLite資料庫中題庫資料
if(tab==MyTag.QUE)
cursor = ToolHelper.loadDB(this,
"select que.* from "+table+" where " + field + "='" + value + "' order by type");
else
cursor = ToolHelper.loadDB(this,
"select que.* from "+table+" and " + field + "='" + value + "' order by type");
num = cursor.getCount();
//答案List初始化
anList = new ArrayList<>();
for (int i = 0; i < num; i++) {
anList.add("");
}
//設定進度條
pb = findViewById(R.id.pb);
pb.setMax(num-1);
pb.setProgress(0);
//前後按鈕
imgPre = findViewById(R.id.img_pre);
imgNext = findViewById(R.id.img_next);
imgPre.setOnClickListener(this);
imgNext.setOnClickListener(this);
//設定初始分數
tvScore =findViewById(R.id.tv_num);
tvScore.setText("得分:" + String.valueOf(score )+ "/" +String.valueOf( num));
//設定ViewFlipper
vf=findViewById(R.id.vf);
adapter=new BaseAdapter() {
@Override
public int getCount() {
return num;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
index=position;
createView(position);
return root;
}
};
vf.setAdapter(adapter);
}
//答題卡設定
private void createView(int pos) {
root = LayoutInflater.from(QuestionActivity.this).inflate(R.layout.queitem, null);
tvQue = root.findViewById(R.id.tv_que1);
cb1 = root.findViewById(R.id.cb_choice1);
cb2 = root.findViewById(R.id.cb_choice2);
cb3 = root.findViewById(R.id.cb_choice3);
cb4 = root.findViewById(R.id.cb_choice4);
tvAns = root.findViewById(R.id.tv_answer1);
tvDetail = root.findViewById(R.id.tv_detail1);
tvYou = root.findViewById(R.id.tv_you);
//擷取資料
cursor.moveToPosition(pos);
type = cursor.getString(cursor.getColumnIndex("type"));
que = cursor.getString(cursor.getColumnIndex("que"));
A = "A."+cursor.getString(cursor.getColumnIndex("choiceA"));
B = "B."+cursor.getString(cursor.getColumnIndex("choiceB"));
C = "C."+cursor.getString(cursor.getColumnIndex("choiceC"));
D = "D."+cursor.getString(cursor.getColumnIndex("choiceD"));
answer = cursor.getString(cursor.getColumnIndex("answer"));
detail = cursor.getString(cursor.getColumnIndex("detail"));
qid = cursor.getString(cursor.getColumnIndex("_id"));
//加載内容
tvQue.setText((pos + 1) + ".(" + type + ")" + que);
cb1.setText(A);
cb2.setText(B);
cb3.setText(C);
cb4.setText(D);
cb1.setButtonDrawable(R.drawable.cb);
cb2.setButtonDrawable(R.drawable.cb);
cb3.setButtonDrawable(R.drawable.cb);
cb4.setButtonDrawable(R.drawable.cb);
cb1.setEnabled(true);
cb2.setEnabled(true);
cb3.setEnabled(true);
cb4.setEnabled(true);
cb1.setChecked(false);
cb2.setChecked(false);
cb3.setChecked(false);
cb4.setChecked(false);
tvAns.setText("【正确答案】" + answer);
tvDetail.setText("【解析】" + detail);
if (anList.get(pos).equals("")) {
tvAns.setVisibility(View.GONE);
tvYou.setVisibility(View.GONE);
tvDetail.setVisibility(View.GONE);
} else {
//已答題設定為不可操作
disableChecked(pos);
}
//設定目前進度
pb.setProgress(pos);
//設定是否被收藏
if(queCollect()){
isCollect=true;
imgCollect.setImageResource(R.drawable.star_on);
}else {
isCollect=false;
imgCollect.setImageResource(R.drawable.star1);
}
//滑動切換
root.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
float startX=v.getWidth()/2,endX=v.getWidth()/2,min=100;
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
startX=event.getX();
case MotionEvent.ACTION_UP:
endX=event.getX();
break;
}
if (startX - endX > min) {
vf.showNext();
}else if (endX - startX > min) {
vf.showPrevious();
}
return true;
}
});
}
//判斷選擇答案對錯
private void isAnswerTrue(int pos) {
if (cb1.isChecked() || cb2.isChecked() || cb3.isChecked() || cb4.isChecked()) {
//擷取答案
StringBuffer sb = new StringBuffer();
if (cb1.isChecked()) sb.append("A");
if (cb2.isChecked()) sb.append("B");
if (cb3.isChecked()) sb.append("C");
if (cb4.isChecked()) sb.append("D");
String you = sb.toString();
//儲存答案
anList.set(pos, you);
//判斷對錯
if (you.equals(answer)) {
moveCorrect();
} else {
//錯誤則儲存錯題,顯示答案
saveWrong(sb.toString());
disableChecked(pos);
}
}else {
Toast.makeText(QuestionActivity.this, "請選擇答案", Toast.LENGTH_SHORT).show();
}
}
//移除正确題目
@SuppressLint("SetTextI18n")
private void moveCorrect() {
score++;
tvScore.setText("得分:" + String.valueOf(score )+ "/" +String.valueOf( num));
vf.showNext();
int c=ToolHelper.loadDB(this,"select _id from wrong where qid="+qid).getCount();
if(c>0)
ToolHelper.excuteDB(this, "delete from wrong where qid=" +qid);
}
//已做題不可再做
private void disableChecked(int pos) {
tvYou.setText("【你的答案】" + anList.get(pos));
tvAns.setVisibility(View.VISIBLE);
tvDetail.setVisibility(View.VISIBLE);
tvYou.setVisibility(View.VISIBLE);
if (answer.contains("A")) cb1.setButtonDrawable(R.drawable.cb_right);
if (answer.contains("B")) cb2.setButtonDrawable(R.drawable.cb_right);
if (answer.contains("C")) cb3.setButtonDrawable(R.drawable.cb_right);
if (answer.contains("D")) cb4.setButtonDrawable(R.drawable.cb_right);
//設定為不可答題
cb1.setEnabled(false);
cb2.setEnabled(false);
cb3.setEnabled(false);
cb4.setEnabled(false);
}
//儲存錯題
private void saveWrong(String ans) {
int c=ToolHelper.loadDB(this,"select _id from wrong where qid="+qid).getCount();
if(c==0) {
Date date = new Date();
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String mydate = ft.format(date);
ToolHelper.excuteDB(this,
"insert into wrong (_id,qid,answer,anTime) values (" + String.valueOf(Math.random() * 10000) + "," + qid + ",'" + ans + "','" + mydate + "')");
}
}
//判斷目前題目是否被收藏
private boolean queCollect() {
int c=ToolHelper.loadDB(this,"select _id from collection where qid="+qid).getCount();
if(c>0) return true;
else return false;
}
//儲存考試記錄
private void saveExam() {
chronometer.stop();
Date date = new Date();
SimpleDateFormat ft = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
String mytime = chronometer.getText().toString();
String mydate = ft.format(date);
String title=source+"\n"+"("+content+")";
ToolHelper.excuteDB(this, "insert into exam (_id,title,examTime,score,examDate) values (" + String.valueOf(Math.random()*10000)
+",'" + title + "','" + mytime + "'," + score + ",'" + mydate + "')");
Intent intent = new Intent(this, ResultActivity.class);
intent.putExtra("score", score+"/"+num);
intent.putExtra("time", mytime);
intent.putExtra("date", mydate);
intent.putExtra("title",title);
startActivity(intent);
finish();
}
@Override
public void onClick(View v) {
switch (v.getId()){
case R.id.img_next:
vf.showNext();
break;
case R.id.img_pre:
vf.showPrevious();
break;
case R.id.img_collect://收藏
if(!isCollect){
imgCollect.setImageResource(R.drawable.star_on);
ToolHelper.excuteDB(this,"insert into collection (_id,qid) values ("+String.valueOf(Math.random()*10000)+","+qid+")");
Toast.makeText(this,"成功收藏",Toast.LENGTH_SHORT).show();
isCollect=true;
}else {
imgCollect.setImageResource(R.drawable.star1);
ToolHelper.excuteDB(this,"delete from collection where qid="+qid);
Toast.makeText(this,"取消收藏",Toast.LENGTH_SHORT).show();
isCollect=false;
}
break;
case R.id.img_card:
Intent intent=new Intent(this,CardActivity.class);
intent.putExtra("num",num);
intent.putExtra("from",1);
startActivityForResult(intent,MyTag.CARD);
break;
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode==MyTag.CARD&&resultCode==MyTag.CARD){
int select=data.getIntExtra("card",0);
moveToItem(select);
}
super.onActivityResult(requestCode, resultCode, data);
}
//跳轉到指定題目
private void moveToItem(int t) {
if (t != index) {
if(t>index) {
int d= t-index;
for (int i = 0; i < d + 1; i++)
vf.showNext();
}else if(t<index){
int p=index-t;
for (int i = 0; i < p + 1; i++)
vf.showPrevious();
}
}
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
getMenuInflater().inflate(R.menu.que, menu);
return super.onCreateOptionsMenu(menu);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case R.id.que_ok://送出答案
if (index >= num - 1) {
if(!isFirst) {
isAnswerTrue(index);
isFirst = true;
}else {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("是否結束測試?");
builder.setNegativeButton("取消", null);
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
saveExam();
}
});
builder.show();
}
} else {
isAnswerTrue(index);
}
break;
case android.R.id.home://傳回
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setTitle("是否取消測試?");
builder.setNegativeButton("取消", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
}
});
builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
QuestionActivity.this.finish();
}
});
builder.show();
break;
}
return super.onOptionsItemSelected(item);
}
}
activity_card.xml 題号卡
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.lidan.xiao.danquestion.activity.CardActivity">
<GridView
android:id="@+id/gv_card"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:numColumns="5"/>
</LinearLayout>
carditem.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/tv_carditem"
android:layout_width="64dp"
android:layout_height="64dp"
android:gravity="center"
android:background="@android:drawable/picture_frame"/>
public class CardActivity extends AppCompatActivity {
private GridView gv;
private int select,num,from;
private TextView selectView=null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_card);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
setTitle("選擇題号");
Intent intent=getIntent();
num=intent.getIntExtra("num",0);
from=intent.getIntExtra("from",1);
createCard();
}
private void createCard() {
gv=findViewById(R.id.gv_card);
BaseAdapter adapter=new BaseAdapter() {
@Override
public int getCount() {
return num;
}
@Override
public Object getItem(int position) {
return position;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
View view= LayoutInflater.from(CardActivity.this).inflate(R.layout.carditem,null);
TextView tv=view.findViewById(R.id.tv_carditem);
tv.setText(String.valueOf(position+1));
if(from==1){
if(!QuestionActivity.anList.get(position).equals("")){
tv.setTextColor(getResources().getColor(R.color.colorAccent));
}else {
tv.setTextColor(getResources().getColor(R.color.gray));
}
}else if(from==2){
if(!PracticeActivity.anList.get(position).equals("")){
tv.setTextColor(getResources().getColor(R.color.colorAccent));
}else {
tv.setTextColor(getResources().getColor(R.color.gray));
}
}
return view;
}
};
gv.setAdapter(adapter);
gv.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if(selectView!=null) {
selectView.setTextColor(getResources().getColor(R.color.gray));
}
((TextView) view).setTextColor(getResources().getColor(R.color.colorAccent));
selectView= (TextView) view;
select=position;
selectCard();
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
private void selectCard() {
Intent intent1 = new Intent(this, CardActivity.class);
intent1.putExtra("card", select);
//傳回資料到前一個Activity
setResult(MyTag.CARD, intent1);
finish();
}
}
activity_result.xml測試成績
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:fitsSystemWindows="true"
tools:context="com.lidan.xiao.danquestion.activity.ResultActivity">
<include layout="@layout/layout_top2"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="@android:drawable/picture_frame"
android:orientation="vertical"
android:padding="16dp">
<TextView
android:id="@+id/tv_title1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="8dp"
android:textColor="@color/colorPrimaryDark"
android:textSize="14sp" />
<TextView
android:id="@+id/tv_score"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:text="得 分:"
android:textColor="@color/colorAccent"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_time"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:text="答題時間:"
android:textColor="@color/gray"
android:textSize="16sp" />
<TextView
android:id="@+id/tv_date"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="32dp"
android:layout_marginTop="8dp"
android:text="送出時間:"
android:textColor="@color/gray"
android:textSize="16sp" />
</LinearLayout>
<Button
android:id="@+id/bt_record"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="@drawable/bt"
android:textColor="@color/white"
android:text="檢視考試記錄"
android:layout_margin="8dp"/>
</LinearLayout>
public class ResultActivity extends AppCompatActivity {
private String title,date,time,score;
private TextView tvTitle,tvScore,tvDate,tvTime;
private Button bt;
@Override
protected void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_result);
//ActionBar工具欄設定
Toolbar toolbar = findViewById(R.id.toolbar2);
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
Intent intent=getIntent();
title=intent.getStringExtra("title");
date=intent.getStringExtra("date");
time=intent.getStringExtra("time");
score=intent.getStringExtra("score");
tvTitle=findViewById(R.id.tv_title1);
tvScore=findViewById(R.id.tv_score);
tvDate=findViewById(R.id.tv_date);
tvTime=findViewById(R.id.tv_time);
tvTitle.setText(title);
tvScore.append(score);
tvDate.append(date);
tvTime.append(time);
setTitle("測試成績");
bt=findViewById(R.id.bt_record);
bt.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
Intent intent1=new Intent(ResultActivity.this,ExamActivity.class);
startActivity(intent1);
}
});
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()){
case android.R.id.home:
finish();
break;
}
return super.onOptionsItemSelected(item);
}
}
4.項目GitHut位址
https://github.com/xiaolidan00/question
微信關注 “安卓集中營”,擷取更多
或者掃碼關注
一起共同學習探讨