@@ -7,6 +7,9 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_discern.xml" value="0.3223958333333333" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_nav_learn_center.xml" value="0.3223958333333333" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/drawable/svg/drawable/ic_nav_my.xml" value="0.3223958333333333" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/detail_example_flag.xml" value="0.4546296296296296" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/detail_phrase_flag.xml" value="0.4546296296296296" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/detail_reference_flag.xml" value="0.4546296296296296" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/dialog_bottom_bg.xml" value="0.5140625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/et_search_bg.xml" value="0.175" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_delete.xml" value="0.30520833333333336" /> | |||
@@ -26,8 +29,10 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/progress_statistics.xml" value="0.4425925925925926" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/progressbar_countdown_time.xml" value="0.45740740740740743" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_12_white.xml" value="0.5140625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_stroke_gray1.xml" value="0.503125" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_8_stroke_gray2.xml" value="0.48055555555555557" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_toplr_24_white.xml" value="0.5061538461538462" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_rounder_toplr_8_white.xml" value="0.5010416666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/shape_switch_thumb.xml" value="0.14074074074074075" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/spoken_autoplay_btn_text_color_.xml" value="0.5140625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_thumb_selector.xml" value="0.3768518518518518" /> | |||
@@ -38,9 +43,10 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_course_main.xml" value="0.33" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_exam_learn_spell.xml" value="0.47690217391304346" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_base.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_exam.xml" value="0.23632218844984804" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_exam.xml" value="0.25" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_exam_word.xml" value="0.33" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_spell.xml" value="0.47690217391304346" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_word.xml" value="0.33" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_learn_word2.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_main.xml" value="0.5" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> | |||
@@ -58,11 +64,16 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_first.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_learn_center.xml" value="0.25" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/fragment_my.xml" value="0.28229166666666666" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_control_button.xml" value="0.46467391304347827" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_spell_content.xml" value="0.45153985507246375" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_word_choose_content.xml" value="0.45153985507246375" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_exam_word_choose_content.xml" value="0.33" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_spell.xml" value="0.4859375" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_test_statistic.xml" value="0.5" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_title.xml" value="0.2373353596757852" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_title.xml" value="0.5784919653893696" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_learn_word.xml" value="0.390625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_over_number.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_word.xml" value="0.390625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/inc_word_detail.xml" value="0.30538922155688625" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/includ_test_option_item.xml" value="0.45153985507246375" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_main_learn_center_course_progress.xml" value="0.503125" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_main_learn_center_course_type_title.xml" value="0.67" /> | |||
@@ -70,6 +81,7 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_title_bar.xml" value="0.25052083333333336" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_course_lesson.xml" value="0.4785615491009682" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_empty.xml" value="0.4979166666666667" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_historical_route.xml" value="0.4859375" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/item_spell_single_word.xml" value="0.23632218844984804" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_course_progress.xml" value="0.25" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_coursepack.xml" value="0.43500866551126516" /> | |||
@@ -86,6 +98,8 @@ | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_my.xml" value="0.44166666666666665" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_service.xml" value="0.21574074074074073" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_nav_statistics.xml" value="0.44166666666666665" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_play.xml" value="0.503125" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_play_pause.xml" value="0.503125" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_right.xml" value="0.4425925925925926" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_spell.xml" value="0.5061538461538462" /> | |||
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_spoken.xml" value="0.5061538461538462" /> |
@@ -0,0 +1,61 @@ | |||
package com.xkl.cdl | |||
import android.util.TypedValue | |||
import android.view.View | |||
import android.widget.LinearLayout | |||
import android.widget.TextView | |||
import androidx.core.content.ContextCompat | |||
import com.xkl.cdl.databinding.IncWordDetailBinding | |||
/** | |||
* author suliang | |||
* create 2022/4/25 19:14 | |||
* Describe: 扩展 | |||
*/ | |||
/** | |||
* IncWordDetailBinding 扩展,设置词组、例句、参考 | |||
* @receiver IncWordDetailBinding | |||
* @param phrase String? 词组 | |||
* @param example String? 例句 | |||
* @param refrence String? 参考 | |||
*/ | |||
fun IncWordDetailBinding.initValue(phrase : String?, example : String?, refrence : String?){ | |||
phrase?.let { | |||
tvPhraseFlag.visibility = View.VISIBLE | |||
layoutPhrase.run { | |||
visibility = View.VISIBLE | |||
removeAllViews() | |||
val params = LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT) | |||
it.split("\n").forEach { | |||
val child = TextView(context).apply { | |||
layoutParams = params | |||
text = it | |||
setTextColor(ContextCompat.getColor(context, R.color.main_text_color)) | |||
setTextSize(TypedValue.COMPLEX_UNIT_DIP, 14f) | |||
} | |||
addView(child) | |||
} | |||
} | |||
}?:let { | |||
tvPhraseFlag.visibility = View.GONE | |||
layoutPhrase.visibility = View.GONE | |||
} | |||
example?.let { | |||
tvExampleFlag.visibility = View.VISIBLE | |||
tvExample.visibility = View.VISIBLE | |||
}?:let { | |||
tvExampleFlag.visibility = View.GONE | |||
tvExample.visibility = View.GONE | |||
} | |||
refrence?.let { | |||
tvReferenceFlag.visibility = View.VISIBLE | |||
tvReference.visibility = View.VISIBLE | |||
}?:let { | |||
tvReferenceFlag.visibility = View.GONE | |||
tvReference.visibility = View.GONE | |||
} | |||
} |
@@ -0,0 +1,187 @@ | |||
package com.xkl.cdl.adapter | |||
import android.graphics.Color | |||
import android.view.ViewGroup | |||
import android.widget.TextView | |||
import com.suliang.common.base.adapter.BaseAdapterViewHolder | |||
import com.suliang.common.base.adapter.BaseRVAdapter | |||
import com.suliang.common.extension.click | |||
import com.suliang.common.util.StringUtil | |||
import com.xkl.cdl.R | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.data.bean.LearnWord | |||
import com.xkl.cdl.databinding.ItemHistoricalRouteBinding | |||
/** | |||
* author suliang | |||
* create 2022/4/25 16:00 | |||
* Describe: 历史轨迹 | |||
* @param courseType 课程类型 | |||
*/ | |||
class AdapterHistoricalRoute(val courseType : Int) : BaseRVAdapter<LearnWord>() { | |||
//正常颜色 | |||
private val normalColor = Color.parseColor("#606060") | |||
//选中颜色 | |||
private val selectColor = Color.parseColor("#5082E6") | |||
//选中背景 | |||
private val selectBackground = R.drawable.shape_rounder_toplr_8_white | |||
//记录当前显示位置 | |||
private var currentSelectPosition = 0 | |||
//记录上一个选中item的位置 | |||
private var previousSelectPosition = -1 | |||
//是否是历史轨迹最后一个 | |||
val currentIsFirstSelect : Boolean | |||
get() { | |||
return currentSelectPosition == itemCount - 1 | |||
} | |||
/*----------下面三属性为辨音、拼写独有---------------------------------------------------------------------*/ | |||
//当前选中项是否需要显示为横线 | |||
private var currentIsShowLine = false | |||
//上一条选中项是否需要显示为横线 | |||
private var previousIsShowLine = false | |||
//标记历史记录中最后添加的项是否学习完成 | |||
private var lastIsLearnOver = false | |||
override fun coverViewHolder(parent : ViewGroup, viewType : Int) : BaseAdapterViewHolder { | |||
return BaseAdapterViewHolder(inflateBinding(parent, R.layout.item_historical_route)) | |||
} | |||
override fun onBindVH(holder : BaseAdapterViewHolder, position : Int) { | |||
when (courseType) { | |||
AppConstants.COURSE_TYPE_ENGLISH_VOICE, | |||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> bindSpellOrVoice(holder, position) | |||
else -> bindDiscern(holder, position) | |||
} | |||
} | |||
/**认读历史轨迹*/ | |||
private fun bindDiscern(holder : BaseAdapterViewHolder, position : Int) { | |||
val item = getItem(position) | |||
(holder.binding as ItemHistoricalRouteBinding).run { | |||
//赋值 识字课程只显示括号包裹里面的中文内容 | |||
tvHistory.run { | |||
text = when (courseType) { | |||
AppConstants.COURSE_TYPE_CHINESE_LITERACY -> StringUtil.literacyGetWord(item.word) | |||
else -> item.word | |||
} | |||
//设置颜色背景 | |||
when (position) { | |||
currentSelectPosition -> setSelect(this) | |||
else -> setNormal(this) | |||
} | |||
} | |||
root.click { | |||
//选中项点击无效 | |||
if (currentSelectPosition == position) return@click | |||
//点击改变值,并更新显示 | |||
previousSelectPosition = currentSelectPosition | |||
currentSelectPosition = position | |||
notifyItemChanged(previousSelectPosition) | |||
notifyItemChanged(currentSelectPosition) | |||
//回调 | |||
onItemClick.invoke(it, position, item) | |||
} | |||
} | |||
} | |||
private fun bindSpellOrVoice(holder : BaseAdapterViewHolder, position : Int) { | |||
val item = getItem(position) | |||
(holder.binding as ItemHistoricalRouteBinding).run { | |||
//设置颜色背景 | |||
when (position) { | |||
currentSelectPosition -> setSelect(tvHistory) | |||
else -> setNormal(tvHistory) | |||
} | |||
//赋值 | |||
tvHistory.text = when (position) { | |||
currentSelectPosition -> when { | |||
currentIsShowLine -> " -- " | |||
else -> item.word | |||
} | |||
previousSelectPosition -> when { | |||
previousIsShowLine -> "--" | |||
else -> item.word | |||
} | |||
else -> item.word | |||
} | |||
//事件 | |||
root.click { | |||
if (currentSelectPosition == position) return@click | |||
//点击改变选中值与显示 | |||
previousSelectPosition = currentSelectPosition | |||
previousIsShowLine = !(previousSelectPosition == itemCount-1 && lastIsLearnOver) | |||
currentSelectPosition = position | |||
currentIsShowLine = true | |||
notifyItemChanged(previousSelectPosition) | |||
notifyItemChanged(currentSelectPosition) | |||
//事件 | |||
onItemClick.invoke(it,position,item) | |||
} | |||
} | |||
} | |||
/** 设置正常颜色 */ | |||
private fun setNormal(textView : TextView) { | |||
textView.run { | |||
setBackgroundResource(0) | |||
setTextColor(normalColor) | |||
} | |||
} | |||
/**设置选中颜色*/ | |||
private fun setSelect(textView : TextView) { | |||
textView.run { | |||
setBackgroundResource(selectBackground) | |||
setTextColor(selectColor) | |||
} | |||
} | |||
/**辨音、拼写显示的答案后,轨迹显示值*/ | |||
fun showHistoricalRouteValue(){ | |||
currentIsShowLine = false | |||
notifyItemChanged(currentSelectPosition) | |||
} | |||
/** 当前项学习完成 ,判断标记最后一项是否学习完成*/ | |||
fun currentLearnOver(){ | |||
if (currentSelectPosition == itemCount -1 ) lastIsLearnOver = true | |||
} | |||
/** 拼写错误,需要在点击下一条时,移除当前item项 */ | |||
fun spellLastLearnError(){ | |||
removeData(currentSelectPosition) | |||
} | |||
override fun setData(data : MutableList<LearnWord>?) { | |||
currentSelectPosition = 0 | |||
previousSelectPosition = -1 | |||
//拼写值 | |||
currentIsShowLine = true | |||
previousIsShowLine = false | |||
super.setData(data) | |||
} | |||
override fun addData(data : LearnWord?, position : Int?) { | |||
previousSelectPosition = currentSelectPosition | |||
currentSelectPosition = position ?: itemCount | |||
//添加数据拼写辨音初始值 | |||
currentIsShowLine = true | |||
previousIsShowLine = false | |||
lastIsLearnOver = false | |||
super.addData(data, position) | |||
notifyItemChanged(previousSelectPosition) | |||
} | |||
} |
@@ -12,7 +12,7 @@ import com.suliang.common.util.os.ScreenUtil | |||
*/ | |||
class SpellItemDecoration : ItemDecoration() { | |||
private val mDividerWidth = ScreenUtil.dp2px(1f) | |||
private val mDividerWidth = ScreenUtil.dp2px(1f).toInt() | |||
override fun getItemOffsets(outRect : Rect, view : View, parent : RecyclerView, state : RecyclerView.State) { | |||
val chilidCount = parent.adapter!!.itemCount |
@@ -30,7 +30,7 @@ object AppConstants { | |||
const val COURSEPACK_TYPE_CHINESE_LITERACY = 3 | |||
/**课程包类型: categoryId -> 语文拼音 */ | |||
const val COURSEPACK_TYPE_CHINESE_PINYIN = 1 | |||
const val COURSEPACK_TYPE_CHINESE_PINYIN = 5 | |||
/**课程类型: typeId 英语认读*/ |
@@ -11,7 +11,7 @@ import com.xkl.cdl.R | |||
* @property courseType Int 课程类型 | |||
* @property chapterId Long 章节id | |||
* @property lessonId Long 课时id | |||
* @property wordId Long 内容id | |||
* @property wordId Long 内容id 作文知识点时为"knowledge_id" | |||
* @property first Boolean 是否第一次出现 | |||
* @property reviewNum Int 大七次次数 | |||
* @property reviewTime Long 复习时间 | |||
@@ -29,7 +29,7 @@ open class BaseWord(val subjectId: Int, | |||
val chapterId: Long, | |||
val lessonId: Long, | |||
val wordId: Long, | |||
val first: Boolean, | |||
var first: Boolean, | |||
val lessonType: Int) { | |||
/** 大复习次数 */ | |||
var reviewNum: Int = 0 |
@@ -28,7 +28,7 @@ class LearnWord(subjectId: Int, | |||
lessonType) { | |||
var word: String? = null //词汇 | |||
var word: String = "" //词汇 | |||
var phonetic_uk: String? = null // 英式音标 | |||
var phonetic_us: String? = null // 美式音标 | |||
var phonetic_cn: String? = null // 中文拼音 |
@@ -19,6 +19,7 @@ import com.xkl.cdl.data.manager.FilePathManager | |||
import io.reactivex.rxjava3.annotations.NonNull | |||
import net.sqlcipher.database.SQLiteDatabase | |||
import java.io.File | |||
import java.lang.StringBuilder | |||
/** | |||
* author suliang | |||
@@ -369,6 +370,18 @@ object DBCourseManager { | |||
} | |||
} | |||
/** | |||
* 查询学习数据,结果为单词类型,其中作文知识点为单独查询 | |||
* @param dbcb DbControlBase | |||
* @param lesson Lesson | |||
* @return List<LearnWord> | |||
*/ | |||
fun queryLearnData(dbcb : DbControlBase, lesson : Lesson) : List<LearnWord> { | |||
return when (dbcb.courseType) { | |||
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> queryLearnDataForCompositionKnowledge(dbcb, lesson) | |||
else -> queryLearnDataForWord(dbcb, lesson) | |||
} | |||
} | |||
/** | |||
* 查询学习数据 | |||
@@ -378,7 +391,7 @@ object DBCourseManager { | |||
* @return List<LearnWord>? | |||
*/ | |||
@SuppressLint("Range") | |||
fun queryLearnDataForWord(dbcb : DbControlBase, lesson : Lesson) : @NonNull List<LearnWord> { | |||
private fun queryLearnDataForWord(dbcb : DbControlBase, lesson : Lesson) : @NonNull List<LearnWord> { | |||
val result = mutableListOf<LearnWord>() | |||
open(dbcb) | |||
//从lesson已学位置开始获取数据 | |||
@@ -405,7 +418,7 @@ object DBCourseManager { | |||
word = getString(getColumnIndex("word")) | |||
basic_explanation = getString(getColumnIndex("basic_explaination")) | |||
extend_explanation = getString(getColumnIndex("all_explaination")) | |||
phrase = getString(getColumnIndex("pharse")) | |||
phrase = getString(getColumnIndex("phrase")) | |||
example = getString(getColumnIndex("example")) | |||
reference = getString(getColumnIndex("reference")) | |||
@@ -433,14 +446,62 @@ object DBCourseManager { | |||
return result | |||
} | |||
/** | |||
* 作文知识点数据学习数据查询 | |||
* @param dbcb DbControlBase | |||
* @param lesson Lesson | |||
* @return List<LearnWord> | |||
*/ | |||
@SuppressLint("Range") | |||
private fun queryLearnDataForCompositionKnowledge(dbcb : DbControlBase, lesson : Lesson) : List<LearnWord> { | |||
val result = mutableListOf<LearnWord>() | |||
open(dbcb) | |||
//从lesson已学位置开始获取数据 | |||
val needLearnIds = lesson.wordIds.subList(lesson.learnedIndex + 1, lesson.wordIds.size) | |||
val wordIds = StringBuilder() //ids集合 | |||
val sortSqlBuilder = StringBuilder() //排序value | |||
needLearnIds.forEachIndexed { index, value -> | |||
sortSqlBuilder.append(" when knowledge_id = $value then $index ") | |||
when (needLearnIds.lastIndex) { | |||
index -> wordIds.append(value) | |||
else -> wordIds.append(value).append(",") | |||
} | |||
} | |||
val sql = | |||
"SELECT * FROM knowledge WHERE chapter_id = ${lesson.chapterId} AND knowledge_id in ($wordIds) ORDER by CASE $sortSqlBuilder END" | |||
mDataBase?.rawQuery(sql, null)?.run { | |||
while (moveToNext()) { | |||
//学习单词实体 | |||
result.add(LearnWord(dbcb.subjectId, | |||
dbcb.coursePackId, | |||
dbcb.courseId, | |||
dbcb.coursePackType, | |||
dbcb.courseType, | |||
lesson.chapterId, | |||
lesson.lessonId, | |||
getLong(getColumnIndex("knowledge_id")), | |||
true, | |||
lesson.lessonType).apply { | |||
word = getString(getColumnIndex("title")) | |||
basic_explanation = getString(getColumnIndex("explaination")) | |||
example = getString(getColumnIndex("example")) | |||
reference = getString(getColumnIndex("reference")) | |||
}) | |||
} | |||
close() | |||
} | |||
return result | |||
} | |||
/**获取图片*/ | |||
fun queryPhoto(dbControlBase : DbControlBase, wordId : Long) : ByteArray? { | |||
open(dbControlBase) | |||
var result : ByteArray? = null | |||
val sql = "SELECT photo FROM res WHERE word_id = $wordId" | |||
mDataBase?.rawQuery(sql,null)?.apply { | |||
while (moveToNext()){ | |||
mDataBase?.rawQuery(sql, null)?.apply { | |||
while (moveToNext()) { | |||
result = getBlob(0) | |||
} | |||
close() |
@@ -263,7 +263,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> { | |||
} | |||
else -> { | |||
wordChooseBinding.tvWord.setOnClickListener(ivVoiceClick) | |||
wordChooseBinding.incWord.tvWord.setOnClickListener(ivVoiceClick) | |||
wordChooseBinding.ivVoice.setOnClickListener(ivVoiceClick) | |||
} | |||
} | |||
@@ -311,7 +311,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
//未答和正确都更新显示正确的项 错误同时显示正确和错误的项 | |||
wordChooseBinding.run { | |||
ivVoice.visibility = View.GONE | |||
tvWord.visibility = View.VISIBLE | |||
incWord.tvWord.visibility = View.VISIBLE | |||
//显示正确项 | |||
vm.optionList[vm.currentCorrectPosition].run { | |||
root.setBackgroundResource(vm.correctBg) | |||
@@ -380,7 +380,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
} | |||
private fun initChooseUIData(examBean : ExamBean) { | |||
wordChooseBinding.tvWord.text = examBean.word | |||
wordChooseBinding.incWord.tvWord.text = examBean.word | |||
wordChooseBinding.progressWordCountdownTime.run { | |||
max = vm.currentMaxTime | |||
progress = vm.currentMaxTime | |||
@@ -397,7 +397,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
} | |||
private fun initVoiceUIData(examBean : ExamBean) { | |||
wordChooseBinding.tvWord.run { | |||
wordChooseBinding.incWord.tvWord.run { | |||
text = examBean.word | |||
visibility = View.GONE | |||
} | |||
@@ -416,12 +416,12 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
} | |||
private fun initSpokenUIData(examBean : ExamBean) { | |||
wordChooseBinding.tvWord.text = examBean.word | |||
wordChooseBinding.incWord.tvWord.text = examBean.word | |||
if (examBean.questionIsAudio) { | |||
wordChooseBinding.tvWord.visibility = View.GONE | |||
wordChooseBinding.incWord.tvWord.visibility = View.GONE | |||
wordChooseBinding.ivVoice.visibility = View.VISIBLE | |||
} else { | |||
wordChooseBinding.tvWord.visibility = View.VISIBLE | |||
wordChooseBinding.incWord.tvWord.visibility = View.VISIBLE | |||
wordChooseBinding.ivVoice.visibility = View.GONE | |||
} | |||
wordChooseBinding.progressWordCountdownTime.visibility = View.GONE | |||
@@ -447,7 +447,7 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
private fun initSpellUIData(examBean : ExamBean) { | |||
spellBinding.tvExplain.text = examBean.correct //释义 | |||
//初始显示word的时候,文字置空,颜色修改为黑色 | |||
spellBinding.tvWord.run { | |||
spellBinding.incWord.tvWord.run { | |||
text = "" | |||
setTextColor(ContextCompat.getColor(this@LearnExamActivity, R.color.main_text_color)) | |||
} | |||
@@ -546,16 +546,16 @@ class LearnExamActivity : BaseActivityVM<ActivityLearnExamBinding, LearnExamView | |||
when { | |||
isOver -> { //拼写结束 | |||
//设置正确的值 | |||
spellBinding.tvWord.setTextColor(ContextCompat.getColor(this, R.color.red_1)) | |||
spellBinding.tvWord.text = correctValue | |||
spellBinding.incWord.tvWord.setTextColor(ContextCompat.getColor(this, R.color.red_1)) | |||
spellBinding.incWord.tvWord.text = correctValue | |||
//拼写结束 | |||
vm.spellOver(selectedValue.toString(), errorSize) | |||
//执行当前的单词发音 延迟发音 | |||
spellBinding.tvWord.postDelayed({ ivVoiceClick(spellBinding.tvWord) }, 200) | |||
spellBinding.incWord.tvWord.postDelayed({ ivVoiceClick(spellBinding.incWord.tvWord) }, 200) | |||
} | |||
else -> { | |||
//设置为选中的值 | |||
spellBinding.tvWord.text = selectedValue | |||
spellBinding.incWord.tvWord.text = selectedValue | |||
} | |||
} | |||
spellBinding.spellRecyclerView.scrollToPosition(nextPosition) |
@@ -1,15 +1,212 @@ | |||
package com.xkl.cdl.module.learn | |||
import androidx.appcompat.app.AppCompatActivity | |||
import android.content.Context | |||
import android.os.Bundle | |||
import android.text.SpannableStringBuilder | |||
import android.text.TextUtils | |||
import android.util.TypedValue | |||
import android.view.View | |||
import android.widget.LinearLayout | |||
import android.widget.TextView | |||
import androidx.core.content.ContextCompat | |||
import androidx.lifecycle.ViewModelProvider | |||
import androidx.recyclerview.widget.GridLayoutManager | |||
import androidx.recyclerview.widget.LinearLayoutManager | |||
import androidx.recyclerview.widget.SimpleItemAnimator | |||
import com.suliang.common.base.activity.BaseActivityVM | |||
import com.suliang.common.extension.click | |||
import com.xkl.cdl.R | |||
import com.xkl.cdl.adapter.AdapterHistoricalRoute | |||
import com.xkl.cdl.adapter.AdapterSpell | |||
import com.xkl.cdl.adapter.itemdecoration.SpellItemDecoration | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.data.bean.LearnWord | |||
import com.xkl.cdl.data.manager.UserInfoManager | |||
import com.xkl.cdl.databinding.ActivityLearnWordBinding | |||
import com.xkl.cdl.databinding.IncLearnSpellBinding | |||
import com.xkl.cdl.databinding.IncLearnWordBinding | |||
import com.xkl.cdl.databinding.IncWordDetailBinding | |||
import com.xkl.cdl.initValue | |||
/** | |||
* 正常的学习、复习、自动播放 | |||
*/ | |||
class LearnWordActivity : AppCompatActivity() { | |||
override fun onCreate(savedInstanceState: Bundle?) { | |||
super.onCreate(savedInstanceState) | |||
setContentView(R.layout.activity_learn_word) | |||
class LearnWordActivity : BaseActivityVM<ActivityLearnWordBinding, LearnWordViewModel>() { | |||
//历史轨迹适配器 | |||
private lateinit var adapterHistorical : AdapterHistoricalRoute | |||
//历史轨迹布局管理器 | |||
private val historicalLayoutManager = LinearLayoutManager(this, LinearLayoutManager.HORIZONTAL, true) | |||
//认读、辨音的内容布局 | |||
private lateinit var bindingWord : IncLearnWordBinding | |||
//拼写内容布局 | |||
private lateinit var bindingSpell : IncLearnSpellBinding | |||
//拼写单词RecyclerView适配器 | |||
private lateinit var spellAdapter : AdapterSpell | |||
//拼写是否可纠错的状态值 | |||
private val SPELL_TAG_ALL_RIGHT = 1 //全对 | |||
private val SPELL_TAG_IN_ERROR = 2 //可纠错 | |||
override fun initViewModel() : LearnWordViewModel { | |||
return ViewModelProvider(this)[LearnWordViewModel::class.java] | |||
} | |||
override fun initActivity(savedInstanceState : Bundle?) { | |||
initTitle() | |||
initBanner() | |||
initHistoricalRoute() | |||
initContentBinding() | |||
initControlButton() | |||
} | |||
/** 横幅 自动播放 与 复习时使用 */ | |||
private fun initBanner() { | |||
// TODO: 2022/4/25 初始化横幅,默认隐藏 | |||
} | |||
/** 标题初始 */ | |||
private fun initTitle() { | |||
binding.incLearnTitle.run { | |||
showProgress = false | |||
imgBack.click { onBackPressed() } | |||
tvTitle.text = vm.learnData.lesson.lessonName | |||
when (vm.learnData.lesson.coursePackType) { | |||
AppConstants.COURSEPACK_TYPE_CHINESE_COMPOSITION, AppConstants.COURSEPACK_TYPE_CHINESE_LITERACY, AppConstants.COURSEPACK_TYPE_CHINESE_PINYIN -> { | |||
voiceSwitch.visibility = View.GONE | |||
vm.defaultSoundWay = AppConstants.SOUND_TYPE_CN | |||
} | |||
else -> { | |||
voiceSwitch.setSoundWay(UserInfoManager.getDefaultSoundWay()) | |||
voiceSwitch.soundWayChange.observe(this@LearnWordActivity) { | |||
vm.defaultSoundWay = it | |||
UserInfoManager.putDefaultSoundWay(it) | |||
if (this@LearnWordActivity::spellAdapter.isInitialized) { | |||
spellAdapter.defaultSoundWay = it | |||
} | |||
} | |||
} | |||
} | |||
} | |||
} | |||
/** 历史轨迹初始 */ | |||
private fun initHistoricalRoute() { | |||
adapterHistorical = AdapterHistoricalRoute(vm.learnData.lesson.courseType).apply { | |||
onItemClick = { v : View, position : Int, item : LearnWord -> | |||
} | |||
} | |||
binding.rvHistoricalRoute.apply { | |||
layoutManager = historicalLayoutManager | |||
adapter = adapterHistorical | |||
} | |||
} | |||
/** 布局内容初始 */ | |||
private fun initContentBinding() { | |||
when (vm.learnData.lesson.courseType) { | |||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> { | |||
bindingSpell = IncLearnSpellBinding.inflate(layoutInflater, binding.containerLayout, true) | |||
//初始拼写列表 | |||
bindingSpell.spellRecyclerView.run { | |||
layoutManager = GridLayoutManager(this@LearnWordActivity, 2, GridLayoutManager.HORIZONTAL, false) | |||
addItemDecoration(SpellItemDecoration()) | |||
setHasFixedSize(true) | |||
(itemAnimator as SimpleItemAnimator).supportsChangeAnimations = false | |||
spellAdapter = AdapterSpell().apply { | |||
onItemSpellingClickListener = itemSpellingClick | |||
defaultSoundWay = vm.defaultSoundWay | |||
} | |||
adapter = spellAdapter | |||
} | |||
//拼写纠错按钮 | |||
bindingSpell.tvControlError.click { | |||
when (it.tag as Int) { | |||
SPELL_TAG_ALL_RIGHT -> vm.currentSpellIsCorrect = false | |||
SPELL_TAG_IN_ERROR -> { | |||
vm.currentSpellIsCorrect = true | |||
//下一条显示 | |||
binding.incControlButton.tvLeft.visibility = View.VISIBLE | |||
//取消纠错点击 | |||
spellAdapter.isErrorRecovery = false | |||
} | |||
} | |||
it.visibility = View.INVISIBLE | |||
} | |||
} | |||
else -> { | |||
bindingWord = IncLearnWordBinding.inflate(layoutInflater, binding.containerLayout, true) | |||
} | |||
} | |||
} | |||
//初始化按钮 | |||
private fun initControlButton() { | |||
when (vm.learnData.lesson.courseType) { | |||
AppConstants.COURSE_TYPE_ENGLISH_SPELL -> { | |||
binding.incControlButton.run { | |||
tvLeft.visibility = View.INVISIBLE | |||
tvCenter.visibility = View.INVISIBLE | |||
tvRight.visibility = View.INVISIBLE | |||
//设置为下一条 | |||
tvLeft.setText(R.string.control_next) | |||
} | |||
} | |||
//知识点学习的时候,需要将重读按钮隐藏 | |||
AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> binding.incControlButton.tvRight.visibility = View.INVISIBLE | |||
//其他课程默认按钮全部显示 | |||
} | |||
} | |||
override fun loadData() { | |||
binding.incDetail.initValue("","","") | |||
} | |||
/** | |||
* 拼写时的点击事件 | |||
* @param selectedValue 选择的值 | |||
* @param nextPosition 下一个item的位置,拼写未完成时为下一列的位置,拼写完成为错误的第一个位置 | |||
* @param isOver 拼写是否完成 为true时则判断为拼写完成 | |||
* @param correctValue 正确的拼写值,但未选中的赋值了颜色 | |||
* @param errorSize 错误的个数,拼写完成后才会有这个值 | |||
*/ | |||
private val itemSpellingClick = | |||
{ selectedValue : SpannableStringBuilder, nextPosition : Int, isOver : Boolean, correctValue : SpannableStringBuilder, errorSize : Int -> | |||
when { | |||
isOver -> { //拼写结束 | |||
//设置正确的值 | |||
bindingSpell.incWord.tvWord.setTextColor(ContextCompat.getColor(this, R.color.red_1)) | |||
bindingSpell.incWord.tvWord.text = correctValue | |||
//拼写结束 | |||
// vm.spellOver(selectedValue.toString(), errorSize) | |||
//执行当前的单词发音 延迟发音 | |||
// bindingSpell.incWord.tvWord.postDelayed({ ivVoiceClick(spellBinding.incWord.tvWord) }, 200) | |||
} | |||
else -> { | |||
//设置为选中的值 | |||
bindingSpell.incWord.tvWord.text = selectedValue | |||
} | |||
} | |||
bindingSpell.spellRecyclerView.scrollToPosition(nextPosition) | |||
} | |||
/** 返回 */ | |||
override fun onBackPressed() { | |||
when { | |||
vm.isAllOver -> finish() | |||
else -> "" | |||
} | |||
} | |||
} |
@@ -0,0 +1,22 @@ | |||
package com.xkl.cdl.module.learn | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.data.DataTransferHolder | |||
import com.xkl.cdl.data.bean.intentdata.LearnData | |||
/** | |||
* 正常的学习、复习、自动播放 | |||
*/ | |||
class LearnWordViewModel : LearnBaseViewModel() { | |||
//默认发音 | |||
var defaultSoundWay : Int = 0 | |||
//操作数据 | |||
val learnData = DataTransferHolder.instance.getData<LearnData>().apply { | |||
DataTransferHolder.instance.clear() | |||
} | |||
//记录拼写的最终结果 | |||
var currentSpellIsCorrect = false | |||
} |
@@ -7,14 +7,17 @@ import com.suliang.common.base.fragment.BaseFragmentVM | |||
import com.suliang.common.eventbus.LiveDataBus | |||
import com.xkl.cdl.adapter.AdapterLesson | |||
import com.xkl.cdl.data.AppConstants | |||
import com.xkl.cdl.data.DataTransferHolder | |||
import com.xkl.cdl.data.bean.LearnDialogBean | |||
import com.xkl.cdl.data.bean.course.ExamBean | |||
import com.xkl.cdl.data.bean.course.Lesson | |||
import com.xkl.cdl.data.bean.intentdata.ExamData | |||
import com.xkl.cdl.data.bean.intentdata.LearnData | |||
import com.xkl.cdl.data.event.LearnEventData | |||
import com.xkl.cdl.data.manager.CourseManager | |||
import com.xkl.cdl.databinding.FragmentCourseLessonBinding | |||
import com.xkl.cdl.dialog.LearnDialog | |||
import com.xkl.cdl.module.learn.LearnWordActivity | |||
/** | |||
* 课程章节目录 | |||
@@ -109,16 +112,17 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
private val onLessonClick : (v:View,position: Int, lesson: Lesson) -> Unit = { view, position, entity -> | |||
when(entity.lessonType){ | |||
AppConstants.LESSON_TYPE_WORD -> { | |||
if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做 | |||
startLearn(entity) | |||
/* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做 | |||
//弹窗显示学前测试提示 | |||
showLessonBeforeTestStartDialog(entity) | |||
}else if (!entity.learnIsOver){ | |||
}else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习 | |||
startLearn(entity) | |||
}else if (entity.afterTestScore != AppConstants.NOT_DOING){ | |||
loadLessonAfterTest(entity) | |||
}else{ //当前课时学习完成的弹窗 | |||
showLessonAllOverDialog(entity) | |||
} | |||
}*/ | |||
} | |||
AppConstants.LESSON_TYPE_SENTENCE -> { | |||
@@ -175,6 +179,18 @@ class CourseLessonFragment : BaseFragmentVM<FragmentCourseLessonBinding, CourseM | |||
} | |||
} | |||
/** | |||
* 查询课时数据,并开始学习,进入学习界面 | |||
* @param lesson Lesson 课时 | |||
*/ | |||
private fun startLearn(lesson : Lesson){ | |||
vm.loadLessonLearnData(lesson).observe(this){ | |||
DataTransferHolder.instance.putData(value = it) | |||
startActivity(LearnWordActivity::class.java) | |||
} | |||
} | |||
/** 开始课时学后测试 | |||
* 请求数据后,直接开始跳转 | |||
*/ |
@@ -117,10 +117,10 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
* @param lesson Lesson 课时 | |||
* @return MutableLiveData<LearnData> | |||
*/ | |||
fun loadLessonLearnForWord(lesson : Lesson): MutableLiveData<LearnData>{ | |||
fun loadLessonLearnData(lesson : Lesson): MutableLiveData<LearnData>{ | |||
val result = MutableLiveData<LearnData>() | |||
Observable.create<List<LearnWord>> { | |||
it.onNext(DBCourseManager.queryLearnDataForWord(dbControlBase, lesson)) | |||
it.onNext(DBCourseManager.queryLearnData(dbControlBase, lesson)) | |||
it.onComplete() | |||
}.compose(diskIo2Main()) | |||
.subscribe { | |||
@@ -128,7 +128,6 @@ class CourseMainFragmentViewModel(val courseIndex : Int) : BaseViewModel() { | |||
learnWordList = it | |||
} | |||
} | |||
return result | |||
} | |||
@@ -1,103 +1,349 @@ | |||
package com.xkl.cdl.util | |||
import com.xkl.cdl.data.bean.BaseWord | |||
import java.io.* | |||
import java.util.* | |||
/** | |||
* author suliang | |||
* create 2022/4/22 17:12 | |||
* Describe: 规则 | |||
* @property originList 源数据 | |||
* @property cycleTime 循环次数 | |||
* create 2021/1/18 13:48 | |||
* Describe: 学习工具类 | |||
* @property originLearnList 源数据 | |||
* @property isSpellModel 是否是拼写模式 | |||
* @property examErrorsMap 学前总和章前错误列表 | |||
*/ | |||
class LearnRuleUtil<T : BaseWord>(private val originList : List<T>, private val cycleTime : Int) { | |||
//源数据学习位置 | |||
private var originLearnPosition : Int = 0 | |||
//学习列表位置 | |||
private var currentLearnPosition : Int = -1 | |||
//学习列表数据 | |||
private var currentList = mutableListOf<T?>(null) | |||
//当前答题是否错误 | |||
class LearnRuleUtil<T : BaseWord> constructor(val originLearnList : List<T>, | |||
isSpellModel : Boolean, | |||
val examErrorsMap : Map<String, Boolean>?) { | |||
//错误时循环插入间隔 | |||
private var insertInterval : IntArray = when { | |||
isSpellModel -> intArrayOf(1, 2, 3, 5) | |||
else -> intArrayOf(1, 2, 3, 5, 7, 10, 15) | |||
} | |||
//当前用于学习的列表: 学习数据从该列表中获取, 并放入第一个数据为null | |||
private var currentLearnList : MutableList<T?> = mutableListOf(null) | |||
//源数据学习的位置 | |||
private var originLearnPosition = -1 | |||
//学习列表学习的位置 | |||
private var currentLearnPosition = -1 | |||
//外部选择结果的记录 记录当前点击是否错误: 点击后需修改,用于获取下一条时进行判断 | |||
private var currentIsError = false | |||
//学前总和课时前测试错误集合 | |||
var examErrorMap = hashMapOf<String,Boolean>() | |||
//新错误集合 | |||
var newErrorMap = hashMapOf<String,Boolean>() | |||
//第一次点击正确的集合, 如果后面再点击错误,需要移除并添加到错误集合中 | |||
var newCorrectMap = hashMapOf<String,Boolean>() | |||
//学习错误的集合: 本次点击的新错误(不包含 examErrorsMap 中的错误) | |||
var currentErrorMap : MutableMap<String, Boolean> = HashMap() | |||
private set | |||
//学习正确的集合: 存放学习中第一次正确的单词 | |||
var currentCorrectMap : MutableMap<String, Boolean> = HashMap() | |||
private set | |||
/** | |||
* 获取下一条数据,返回是否学习完成 | |||
*/ | |||
val loadNext : T? | |||
get() { | |||
return when { | |||
currentIsError || isHaveNext -> nextWord() | |||
else -> null | |||
} | |||
} | |||
//1、如果当前学习下标为-1,即第一次进入学习,直接返true | |||
//2、判断源数据是否学习完成 | |||
//源数据学习未完,返回true ,还有未学单词 | |||
//源数据学完,判断学习列表是否学习结束 | |||
// 而在源数据没有获取到数据的时候,当前数据currentList的当前数据下坐标会走到下一个有效值位置 | |||
// 取出当前学习的单词,当前单词不会为null,会有源数据进行空位填充, | |||
//获取下一个不为null 且和当前数据不一样的数据 | |||
//如果获取不到下一个不为空的数据,则还有下一条,否则结束了 | |||
fun getNext(): T? { | |||
if (currentIsError || isHaveNext()){ | |||
return nextWord() | |||
//是否有下一条数据 | |||
val isHaveNext : Boolean | |||
get() { | |||
//1、如果当前学习下标为-1,即第一次进入学习,直接返true | |||
if (currentLearnPosition == -1) return true | |||
//2、判断源数据是否学习完成 | |||
val originLearnEnd = isLearnOverForOrigin() | |||
//源数据学习未完,返回true ,还有未学单词 | |||
if (!originLearnEnd) return true | |||
//源数据学完,判断学习列表是否学习结束 | |||
// 而在源数据没有获取到数据的时候,当前数据currentList的当前数据下坐标会走到下一个有效值位置 | |||
// 取出当前学习的单词,当前单词不会为null,会有源数据进行空位填充, | |||
val curentLearnWord = currentLearnList[currentLearnPosition]!! | |||
//获取下一个不为null 且和当前数据不一样的数据 | |||
var nextWord : T? = null | |||
for (i in currentLearnPosition until currentLearnList.size) { | |||
val word : T? = currentLearnList[i] | |||
if (word != null && word.wordId != curentLearnWord.wordId) { | |||
nextWord = word | |||
break | |||
} | |||
} | |||
//如果获取不到下一个不为空的数据,则还有下一条,否则结束了 | |||
return nextWord != null | |||
} | |||
//有下一条数据的情况下获取下一条 | |||
private fun nextWord() : T? { | |||
currentLearnPosition++ | |||
return currentLearnList.getOrNull(currentLearnPosition) ?: let { | |||
// //当前学习列表获取的下一条数据为空,则从源数据集合获取数据 | |||
originNexWord?.let { //源数据还有数据 | |||
val key = "${it.chapterId}_${it.lessonId}_${it.wordId}" | |||
when { | |||
//是否测试错误 | |||
isInExamErrorMap(key) -> insertErrorWord(it, true) //对当前集合进行插入,在学前测试错误集合中的内容,直接从第一次错误开始 | |||
else -> when { //源数据不为错误数据,需要将源数据添加到当前学习列表中,可能直接替换 或直接添加 | |||
currentLearnList.size > currentLearnPosition -> currentLearnList[currentLearnPosition] = it | |||
else -> currentLearnList.add(currentLearnPosition, it) | |||
} | |||
} | |||
//获取当前位置的值:重新获取的原因是:当为测试错误时,将修改数据的次数 | |||
currentLearnList[currentLearnPosition] | |||
} ?: getCurrentListNextWordForCycle() //源数据没有数据了,继续获取下一条数据,因下一条数据可能为null,所有需要走递归,找不为空的数据 | |||
} | |||
return null | |||
} | |||
/** | |||
* 是否还有下一单词 | |||
* @return Boolean | |||
* 递归获取当前列表的下一条不为空的数据 | |||
*/ | |||
private fun isHaveNext():Boolean{ | |||
//如果当前学习下标为-1,即第一次进入学习,直接返true | |||
if (currentLearnPosition == -1) return true | |||
//元数据是否学习完成,未学习完成,则还有学习数据, 元数据学习完成,还需要判断当前学习列表是否学习完成 | |||
if (!isLearnOverForOrigin()) return true | |||
//判断当前列表是否学习完成 | |||
val currentLearnWord = currentList[currentLearnPosition]!! | |||
var nextWord: T? = null | |||
//循环找寻与当前word不一样的数据 | |||
if (currentLearnPosition + 1 < currentList.size-1) { | |||
for (i in currentLearnPosition + 1 .. currentList.size - 1) { | |||
currentList[i]?.let { | |||
if (currentLearnWord.wordId != it.wordId ){ | |||
nextWord = it | |||
private fun getCurrentListNextWordForCycle() : T? { | |||
currentLearnPosition++ | |||
return when { | |||
currentLearnList.size > currentLearnPosition -> currentLearnList[currentLearnPosition] | |||
?: getCurrentListNextWordForCycle() | |||
else -> null | |||
} | |||
} | |||
/** 获取原数据集合的下一条数据 */ | |||
private val originNexWord : T? | |||
get() { | |||
originLearnPosition++ | |||
return originLearnList.getOrNull(originLearnPosition) | |||
} | |||
/** 替换错误单词数据位置,为空占位,将后面的相同单词替换为空,便于错误后,重新排列错误数据 */ | |||
private fun replaceErrorToNull(item : T) { | |||
run cyclerFor@{ | |||
for (i in currentLearnPosition + 1 until currentLearnList.size) { | |||
currentLearnList[i]?.let { | |||
//为相同单词 | |||
if (item.wordId == it.wordId && item.lessonId == it.lessonId && item.chapterId == it.chapterId) { | |||
currentLearnList.set(i, null) | |||
if (it.repeatNum == insertInterval.size) { | |||
return@cyclerFor | |||
} | |||
} | |||
} | |||
if (nextWord != null) break | |||
} | |||
} | |||
//如果获取不到下一个不为空的数据,则还有下一条,否则结束了 | |||
return nextWord != null | |||
} | |||
/** 计算当前列表值,并进行扩容 */ | |||
private fun dilatationSpace() { | |||
var spaceCount = currentLearnPosition //需要扩容的空间 | |||
for (i in insertInterval.indices) { | |||
spaceCount += insertInterval[i] + 1 //扩容需用空间 当前 + 间隔 + 1,最后的1即位需要替换的位置 | |||
} | |||
dilatationToPosition(spaceCount) | |||
} | |||
/** 扩容至指定位置,并添加空数据占位 */ | |||
private fun dilatationToPosition(insertPosition : Int) { | |||
for (i in currentLearnList.size .. insertPosition) { | |||
currentLearnList.add(null) | |||
} | |||
} | |||
/** | |||
* 插入错误单词 | |||
* @param item 原型单词 | |||
* @param isExamError 是否时长测试列表中的错误 | |||
*/ | |||
private fun insertErrorWord(item : T, isExamError : Boolean) { | |||
var stat : Int | |||
//测试第一次添加时,为当前位置,所以减二用于获取插入前的位置 | |||
stat = if (isExamError) currentLearnPosition - insertInterval[0] - 1 else currentLearnPosition | |||
dilatationSpace() | |||
for (i in 1 .. insertInterval.size) { | |||
val insert = copyWord(item, i) | |||
if (i == 1 && isExamError) { //如果是测试错误的加入,第一次应特殊设置,用于判断为学习进度 | |||
insert?.first = true | |||
} | |||
val insertPosition = stat + insertInterval[i - 1] + 1 //需要插入的位置 | |||
val nextWordPosition = getNextValidPosition(stat) //下一个有效单词的下标 : 开始值为现在传入的值 | |||
val finalInsertPosition = getFinalInsertPosition(stat, insertPosition, nextWordPosition) //获取最终需要插入的位置 | |||
//操作判断是否需要扩容,如果需要则自动扩容 | |||
dilatationToPosition(finalInsertPosition) | |||
//取出当前内容,进行操作: 插入 或 替换 | |||
val t : T? = currentLearnList[finalInsertPosition] | |||
if (null == t) { | |||
currentLearnList[finalInsertPosition] = insert | |||
} else { | |||
currentLearnList.add(finalInsertPosition, insert) | |||
} | |||
stat = finalInsertPosition | |||
} | |||
} | |||
/** | |||
* 源数据是否学习完成 | |||
* 生成一个新的单词对象 | |||
* @param old 用来copy的单词 | |||
* @param num 设置错误次数 | |||
* @return | |||
*/ | |||
fun isLearnOverForOrigin():Boolean{ | |||
return originLearnPosition >= originList.size -1 | |||
private fun copyWord(old : T, num : Int) : T? { | |||
var newWord : T? = null | |||
try { | |||
newWord = copy(old) | |||
newWord.repeatNum = num | |||
newWord.first = false //设置为不为第一次出现的内容 | |||
return newWord | |||
} catch (e : IOException) { | |||
e.printStackTrace() | |||
} catch (e : ClassNotFoundException) { | |||
e.printStackTrace() | |||
} | |||
return null | |||
} | |||
/** | |||
* 获取下一条数据 | |||
* 获取从指定位置向后的有效单词位置 | |||
*/ | |||
private fun nextWord(): T?{ | |||
//声明下一条数据 | |||
var next : T? = null | |||
//当前列表 学习位置+1 | |||
currentLearnPosition ++ | |||
when{ | |||
//从当前集合获取 | |||
currentList.size > currentLearnPosition -> { | |||
private fun getNextValidPosition(startPosition : Int) : Int { | |||
var nextWordPositon = -1 | |||
val currentListSize = currentLearnList.size | |||
for (j in startPosition + 1 until currentListSize) { | |||
if (j < 0) continue //如果在学习时,第一个就是测试的错误,则startPosition为-2,j < 0时,为无效,所以直接跳过 | |||
if (currentLearnList[j] != null) { | |||
nextWordPositon = j | |||
break | |||
} | |||
//从源数据据列表获取 | |||
else -> { | |||
originLearnPosition++ | |||
if (!isLearnOverForOrigin()) { | |||
next = originList[originLearnPosition] | |||
//元数据如果是课时学前或总测的错误数据,那么就需要按照小循环插入 | |||
} | |||
return nextWordPositon | |||
} | |||
/** | |||
* 获取最终获取的插入位置 | |||
* @param insertPosition 应该插入的位置 | |||
* @param nextWordPositon 下一个单词的所在的位置 | |||
*/ | |||
private fun getFinalInsertPosition(currentPosition : Int, insertPosition : Int, nextWordPositon : Int) : Int { | |||
if (nextWordPositon != -1 && insertPosition <= nextWordPositon) { //下一个单词的位置有效,且 插入位置小于或等于下一个的位置 | |||
val isChangePosition = isChangeInsertPosition(insertPosition) | |||
if (isChangePosition) { //如果需要改变位置 | |||
val startItem = currentLearnList[currentPosition]!! //开始位置的单词 | |||
val nextItem = currentLearnList[nextWordPositon]!! //下一个有效位置的单词 | |||
return if (startItem.wordId == nextItem.wordId) { //如果需要插入的单词和下一个有效位置的单词是同一个 | |||
nextWordPositon //如果是同一个,将插入单词放在下一个有效单词之前 | |||
} else { | |||
nextWordPositon + 1 //如果不是同一个单词,则将单词插入下一个单词之后 | |||
} | |||
} | |||
} | |||
return next | |||
return insertPosition | |||
} | |||
/** | |||
* 是否需要改变插入位置 | |||
*/ | |||
private fun isChangeInsertPosition(currentInsertPosition : Int) : Boolean { | |||
//如果有下一个有效单词 且 有效单词位置 大于等于 需要插入的位置 (处理是否需要修改插入位置的改变,避免中间为空数据时不能从原数据中获取数据,而导致出现连续错误单词) | |||
var isChangePosition = false //记录是否需要改变插入位置,避免中间为空数据时不能从原数据中获取数据,而导致出现连续错误单词 | |||
//原数据中剩余学习单词,originlearnPosition为已显示或学习的下坐标 | |||
val originSurplusNum = originLearnList.size - (originLearnPosition + 1) | |||
isChangePosition = if (originSurplusNum > 0) { //原数据中有未学习完的单词 | |||
var nullNum = 0 //记录空数据数量,从当前学习单词的下一个开始,到需要插入的数据中间的空数据数量 | |||
for (k in currentLearnPosition + 1 until currentInsertPosition) { | |||
if (null == currentLearnList[k]) { | |||
nullNum++ | |||
} | |||
} | |||
nullNum > originSurplusNum //如果空数据数量大于源数据未学数据的大小,则需要改变数据位置,改变到下一个有效单词的后面 | |||
} else { | |||
true | |||
} | |||
return isChangePosition | |||
} | |||
/** | |||
* 复制一个对象 | |||
* @param old 原对象 | |||
* @param <T> 泛型 | |||
* @return | |||
* @throws IOException | |||
* @throws ClassNotFoundException | |||
</T> */ | |||
@Throws(IOException::class, ClassNotFoundException::class) | |||
fun <T> copy(old : T) : T { | |||
// 写入字节流 | |||
val baos = ByteArrayOutputStream() | |||
val oos = ObjectOutputStream(baos) | |||
oos.writeObject(old) | |||
// 读取字节流 | |||
val bais = ByteArrayInputStream(baos.toByteArray()) | |||
val ois = ObjectInputStream(bais) | |||
return ois.readObject() as T | |||
} | |||
/** 是否在错误列表中 */ | |||
/** | |||
* 点击正确 | |||
* @param item T 点击单词 | |||
* @param isLearnFirst 是否是新出来的单词,非从历史轨迹中点击的已答过的单词 | |||
*/ | |||
fun correct(item : T, isLearnFirst : Boolean) { | |||
val key : String = "${item.chapterId}_${item.lessonId}_${item.wordId}" | |||
if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key) && !currentCorrectMap.containsKey(key)) { //不为已有错误,操作正确数+1 | |||
currentCorrectMap[key] = true | |||
} | |||
if (isLearnFirst) currentIsError = false | |||
} | |||
/** | |||
* 点击错误 | |||
*/ | |||
fun error(item : T) { | |||
currentIsError = true //定义为学习错误,代表后面还有错误值 | |||
//如果在正确列表中,从正确列表中移除,并添加到错误列表中,正确数-1 ,错误数+1 | |||
//如果是测试前错误不操作正确错误数 | |||
//如果是学习中的错误 ,错误数+1 | |||
val key = "${item.chapterId}_${item.lessonId}_${item.wordId}" | |||
if (currentCorrectMap.containsKey(key)) { | |||
currentCorrectMap.remove(key) | |||
currentErrorMap[key] = true | |||
} else if (!isInExamErrorMap(key) && !isInCurrentErrorMap(key)) { //测试中数据的错误 | |||
currentErrorMap[key] = true | |||
} | |||
//开始进行数据扩容替换 | |||
replaceErrorToNull(item) //替换已有错误为空 | |||
insertErrorWord(item, false) //开始插入 | |||
} | |||
/** | |||
* 是否在学前章前测试的错误集合中 | |||
* @return true在 false不存在 | |||
*/ | |||
fun isInExamErrorMap(key : String) : Boolean { | |||
return examErrorsMap?.getOrDefault(key, null) ?: false | |||
} | |||
/** 是否是在学习的错误列表中 */ | |||
fun isInCurrentErrorMap(key : String) : Boolean { | |||
return currentErrorMap.getOrDefault(key, false) | |||
} | |||
/** 判断源数据中的数据是否已经学习完成:由外部调用,originLearnPosition下标的数据为已经取出来学习的数据,只有为第一个的时候,才判断此方法 */ | |||
fun isLearnOverForOrigin() : Boolean { | |||
return originLearnPosition >= originLearnList.size - 1 | |||
} | |||
} |
@@ -57,7 +57,7 @@ public class MyRankingView extends LinearLayout { | |||
private void initView() { | |||
defaultSize = ScreenUtil.INSTANCE.dp2px(122); //默认大小 | |||
defaultSize = (int) ScreenUtil.INSTANCE.dp2px(122); //默认大小 | |||
mRectF = new RectF(); | |||
if (normalColor != -2 && progressWidth != -2) { |
@@ -27,7 +27,7 @@ class XkLRefreshHeader @JvmOverloads constructor( | |||
init { | |||
orientation = VERTICAL | |||
gravity = Gravity.CENTER | |||
setPadding(0,ScreenUtil.dp2px(8f),0,ScreenUtil.dp2px(8f)) | |||
setPadding(0,ScreenUtil.dp2px(8f).toInt(),0,ScreenUtil.dp2px(8f).toInt()) | |||
LayoutInflater.from(context).inflate(R.layout.smart_refresh_header, this, true) | |||
} | |||
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||
<solid android:color="#40A540" /> | |||
<corners android:radius="2dp" /> | |||
<size | |||
android:width="4dp" | |||
android:height="16dp" /> | |||
</shape> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||
<solid android:color="#F7874F" /> | |||
<corners android:radius="2dp" /> | |||
<size | |||
android:width="4dp" | |||
android:height="16dp" /> | |||
</shape> |
@@ -0,0 +1,8 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||
<solid android:color="#5082E6" /> | |||
<corners android:radius="2dp" /> | |||
<size | |||
android:width="4dp" | |||
android:height="16dp" /> | |||
</shape> |
@@ -0,0 +1,6 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<shape xmlns:android="http://schemas.android.com/apk/res/android"> | |||
<corners android:topLeftRadius="8dp" | |||
android:topRightRadius="8dp"/> | |||
<solid android:color="@color/white"/> | |||
</shape> |
@@ -15,7 +15,9 @@ | |||
<include | |||
android:id="@+id/inc_learn_title" | |||
layout="@layout/inc_learn_title" /> | |||
layout="@layout/inc_learn_title" | |||
app:showProgress="@{true}" | |||
/> | |||
<include | |||
android:id="@+id/inc_statistics" |
@@ -1,9 +1,155 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||
<layout 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" | |||
tools:context=".module.learn.LearnWordActivity"> | |||
xmlns:tools="http://schemas.android.com/tools"> | |||
</androidx.constraintlayout.widget.ConstraintLayout> | |||
<data> | |||
</data> | |||
<androidx.constraintlayout.widget.ConstraintLayout | |||
android:layout_width="match_parent" | |||
android:layout_height="match_parent" | |||
android:background="@color/white" | |||
tools:context=".module.learn.LearnWordActivity"> | |||
<!--标题头部导航--> | |||
<include | |||
android:id="@+id/inc_learn_title" | |||
layout="@layout/inc_learn_title" | |||
app:showProgress="@{false}" /> | |||
<View | |||
android:layout_width="match_parent" | |||
android:layout_height="30dp" | |||
android:background="@color/gray_1" | |||
app:layout_constraintTop_toTopOf="@id/rv_historical_route"/> | |||
<!--历史轨迹--> | |||
<androidx.recyclerview.widget.RecyclerView | |||
android:id="@+id/rv_historical_route" | |||
android:layout_width="wrap_content" | |||
android:layout_height="30dp" | |||
android:orientation="horizontal" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
app:layout_constraintTop_toBottomOf="@+id/inc_learn_title" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
tools:reverseLayout="true" | |||
tools:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | |||
tools:itemCount="1" | |||
android:onItemSelected="1" | |||
app:layout_constraintHorizontal_bias="0" | |||
tools:listitem="@layout/item_historical_route" | |||
/> | |||
<TextView | |||
android:id="@+id/tv_banner" | |||
android:layout_width="match_parent" | |||
android:layout_height="28dp" | |||
android:background="#1A5082E6" | |||
android:gravity="center" | |||
android:text="@string/auto_playing" | |||
android:textColor="@color/theme_color" | |||
android:textSize="@dimen/smallerSize" | |||
app:layout_constraintTop_toBottomOf="@+id/rv_historical_route" | |||
android:visibility="gone"/> | |||
<!--内容布局--> | |||
<FrameLayout | |||
android:id="@+id/container_layout" | |||
android:layout_width="0dp" | |||
android:layout_height="wrap_content" | |||
android:minHeight="190dp" | |||
android:paddingBottom="10dp" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_banner"> | |||
<!-- <include layout="@layout/inc_learn_word" />--> | |||
<!-- <include layout="@layout/inc_learn_spell" />--> | |||
</FrameLayout> | |||
<!--按钮--> | |||
<include | |||
android:id="@+id/inc_control_button" | |||
layout="@layout/inc_control_button" | |||
android:layout_width="0dp" | |||
android:layout_height="56dp" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@id/container_layout" /> | |||
<!--详情--> | |||
<include | |||
android:id="@+id/inc_detail" | |||
layout="@layout/inc_word_detail" | |||
android:layout_width="match_parent" | |||
android:layout_height="0dp" | |||
app:layout_constraintBottom_toTopOf="@+id/tv_use_total_time" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/inc_control_button" | |||
android:visibility="gone" | |||
tools:visibility="visible"/> | |||
<!--总时间--> | |||
<TextView | |||
android:id="@+id/tv_use_total_time" | |||
android:layout_width="wrap_content" | |||
android:layout_height="30dp" | |||
android:gravity="center" | |||
android:text="本次学习 00:00:00" | |||
android:textColor="@color/gray_2" | |||
android:textSize="@dimen/smallerSize" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent"/> | |||
<Button | |||
android:layout_width="wrap_content" | |||
android:layout_height="22dp" | |||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton" | |||
tools:text="暂停播放" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
android:insetTop="0dp" | |||
android:insetBottom="0dp" | |||
android:textColor="@color/theme_color" | |||
app:strokeColor = "@color/theme_color" | |||
app:strokeWidth="@dimen/line_height" | |||
android:layout_marginBottom="4dp" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:textSize="@dimen/smallerSize" | |||
app:icon="@drawable/ic_play_pause" | |||
app:iconSize="16dp" | |||
app:iconTint="@color/theme_color" | |||
app:rippleColor="@color/white"/> | |||
<Button | |||
android:layout_width="wrap_content" | |||
android:layout_height="22dp" | |||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton" | |||
tools:text="停止播放" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
android:insetTop="0dp" | |||
android:insetBottom="0dp" | |||
android:textColor="@color/theme_color" | |||
app:strokeColor = "@color/theme_color" | |||
app:strokeWidth="@dimen/line_height" | |||
android:layout_marginBottom="4dp" | |||
android:layout_marginEnd="@dimen/global_spacing" | |||
android:textSize="@dimen/smallerSize" | |||
app:icon="@drawable/ic_play_stop" | |||
app:iconSize="10dp" | |||
app:iconTint="@color/theme_color" | |||
app:rippleColor="@color/white" | |||
/> | |||
</androidx.constraintlayout.widget.ConstraintLayout> | |||
</layout> |
@@ -0,0 +1,58 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing"> | |||
<Button | |||
android:id="@+id/tv_left" | |||
style="@style/common_button" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/common_button_height" | |||
android:backgroundTint="@color/control_left" | |||
android:gravity="center" | |||
app:cornerRadius="8dp" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toStartOf="@id/tv_center" | |||
app:layout_constraintHorizontal_chainStyle="spread" | |||
app:layout_constraintHorizontal_weight="3" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:text="@string/control_answer" | |||
tools:visibility="visible" /> | |||
<Button | |||
android:id="@+id/tv_center" | |||
style="@style/common_button" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/common_button_height" | |||
android:layout_marginStart="8dp" | |||
android:layout_marginEnd="8dp" | |||
android:backgroundTint="@color/control_center" | |||
android:text="@string/control_error" | |||
app:cornerRadius="8dp" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toStartOf="@+id/tv_right" | |||
app:layout_constraintHorizontal_weight="3" | |||
app:layout_constraintStart_toEndOf="@+id/tv_left" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:visibility="visible" /> | |||
<Button | |||
android:id="@+id/tv_right" | |||
style="@style/common_button" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/common_button_height" | |||
android:backgroundTint="@color/control_right" | |||
android:text="@string/control_reRead" | |||
app:cornerRadius="8dp" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintHorizontal_weight="2" | |||
app:layout_constraintStart_toEndOf="@+id/tv_center" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:visibility="visible" /> | |||
</androidx.constraintlayout.widget.ConstraintLayout> |
@@ -40,22 +40,32 @@ | |||
app:layout_constraintTop_toBottomOf="@+id/tv_explain" | |||
tools:progress="20" /> | |||
<androidx.appcompat.widget.AppCompatTextView | |||
android:id="@+id/tv_word" | |||
android:layout_width="match_parent" | |||
<!-- <androidx.appcompat.widget.AppCompatTextView--> | |||
<!-- android:id="@+id/tv_word"--> | |||
<!-- android:layout_width="match_parent"--> | |||
<!-- android:layout_height="@dimen/height_word"--> | |||
<!-- android:layout_marginTop="@dimen/global_spacing"--> | |||
<!-- android:gravity="center"--> | |||
<!-- tools:text="gradual"--> | |||
<!-- tools:textColor="@color/num0"--> | |||
<!-- android:textSize="@dimen/size_max_word"--> | |||
<!-- app:autoSizeMaxTextSize="@dimen/size_max_word"--> | |||
<!-- app:autoSizeMinTextSize="@dimen/miniSize"--> | |||
<!-- app:autoSizeStepGranularity="1dp"--> | |||
<!-- app:autoSizeTextType="uniform"--> | |||
<!-- app:layout_constraintStart_toStartOf="parent"--> | |||
<!-- app:layout_constraintEnd_toEndOf="parent"--> | |||
<!-- app:layout_constraintTop_toBottomOf="@+id/progress_word_countdown_time" />--> | |||
<include | |||
android:id="@+id/inc_word" | |||
layout="@layout/inc_word" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/height_word" | |||
android:layout_marginTop="@dimen/global_spacing" | |||
android:gravity="center" | |||
tools:text="gradual" | |||
tools:textColor="@color/num0" | |||
android:textSize="@dimen/size_max_word" | |||
app:autoSizeMaxTextSize="@dimen/size_max_word" | |||
app:autoSizeMinTextSize="@dimen/miniSize" | |||
app:autoSizeStepGranularity="1dp" | |||
app:autoSizeTextType="uniform" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/progress_word_countdown_time" /> | |||
app:layout_constraintTop_toBottomOf="@+id/progress_word_countdown_time" | |||
android:layout_marginTop="@dimen/global_spacing"/> | |||
<TextView | |||
android:id="@+id/tv_rule_tip" | |||
@@ -67,7 +77,7 @@ | |||
android:textSize="@dimen/smallerSize" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_word" /> | |||
app:layout_constraintTop_toBottomOf="@+id/inc_word" /> | |||
<androidx.recyclerview.widget.RecyclerView | |||
android:id="@+id/spell_recyclerView" | |||
@@ -81,7 +91,11 @@ | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_rule_tip" | |||
android:layout_marginTop="12dp" | |||
app:layout_constrainedWidth="true"/> | |||
app:layout_constrainedWidth="true" | |||
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager" | |||
tools:itemCount="4" | |||
tools:listitem="@layout/item_spell_single_word" | |||
tools:orientation="horizontal"/> | |||
</androidx.constraintlayout.widget.ConstraintLayout> |
@@ -26,29 +26,16 @@ | |||
app:layout_constraintTop_toTopOf="parent" | |||
android:visibility="gone"/> | |||
<androidx.appcompat.widget.AppCompatTextView | |||
android:id="@+id/tv_word" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/height_word" | |||
android:layout_marginTop="10dp" | |||
android:gravity="center" | |||
tools:text="gradual" | |||
android:textColor="@color/num0" | |||
android:textSize="@dimen/size_max_word" | |||
app:autoSizeMaxTextSize="@dimen/size_max_word" | |||
app:autoSizeMinTextSize="@dimen/miniSize" | |||
app:autoSizeStepGranularity="1dp" | |||
app:autoSizeTextType="uniform" | |||
app:layout_constraintTop_toTopOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" /> | |||
<include | |||
android:id="@+id/inc_word" | |||
layout="@layout/inc_word" /> | |||
<androidx.constraintlayout.widget.Barrier | |||
android:id="@+id/barrier" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
app:barrierDirection="bottom" | |||
app:constraint_referenced_ids="tv_word,iv_voice"/> | |||
app:constraint_referenced_ids="inc_word,iv_voice"/> | |||
<!--单词测试时间--> | |||
<ProgressBar |
@@ -0,0 +1,73 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto" | |||
xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:tools="http://schemas.android.com/tools" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
> | |||
<!-- tools:showIn="@layout/activity_learn_word"--> | |||
<TextView | |||
android:id="@+id/tv_explain" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginTop="14dp" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/bigSize" | |||
android:textStyle="bold" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:text="逐渐的;逐步的逐渐的;逐步的逐渐逐渐的;逐步的逐渐的;逐步的逐渐" /> | |||
<include | |||
android:id="@+id/inc_word" | |||
layout="@layout/inc_word" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/height_word" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_explain" /> | |||
<androidx.recyclerview.widget.RecyclerView | |||
android:id="@+id/spell_recyclerView" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_gravity="center" | |||
android:layout_marginStart="10dp" | |||
android:layout_marginTop="12dp" | |||
android:layout_marginEnd="10dp" | |||
android:background="@color/red_3" | |||
app:layout_constrainedWidth="true" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/inc_word" | |||
tools:itemCount="4" | |||
tools:layoutManager="androidx.recyclerview.widget.GridLayoutManager" | |||
tools:listitem="@layout/item_spell_single_word" | |||
tools:orientation="horizontal" /> | |||
<!--操作失误tip--> | |||
<Button | |||
android:id="@+id/tv_control_error" | |||
style="@style/Widget.MaterialComponents.Button.UnelevatedButton" | |||
android:insetTop="0dp" | |||
android:insetBottom="0dp" | |||
app:cornerRadius="8dp" | |||
app:strokeWidth="@dimen/line_height" | |||
app:strokeColor="@color/theme_color" | |||
android:layout_width="wrap_content" | |||
android:layout_height="32dp" | |||
android:layout_marginTop="10dp" | |||
android:layout_marginEnd="30dp" | |||
android:backgroundTint="@color/white" | |||
android:gravity="center" | |||
android:text="操作失误,我不会" | |||
android:textColor="@color/theme_color" | |||
android:textSize="@dimen/smallerSize" | |||
android:visibility="invisible" | |||
app:layout_constraintRight_toRightOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/spell_recyclerView" | |||
tools:visibility="visible" /> | |||
</androidx.constraintlayout.widget.ConstraintLayout> |
@@ -1,70 +1,82 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" | |||
<layout 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="0dp" | |||
android:layout_height="@dimen/title_bar_height" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:showIn="@layout/activity_learn_exam"> | |||
<ImageView | |||
android:id="@+id/img_back" | |||
android:layout_width="wrap_content" | |||
android:layout_height="match_parent" | |||
android:layout_centerVertical="true" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:scaleType="centerInside" | |||
android:src="@drawable/ic_back" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
<data> | |||
<import type="android.view.View"/> | |||
<variable | |||
name="showProgress" | |||
type="Boolean" /> | |||
</data> | |||
<TextView | |||
android:id="@+id/tv_title" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="66dp" | |||
android:ellipsize="end" | |||
android:maxLines="1" | |||
tools:text="小学英语单词课程小学英语单词课程小学英语单词课程" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/bigSize" | |||
android:textStyle="bold" | |||
app:layout_constrainedWidth="true" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toStartOf="@+id/tv_num_progress" | |||
app:layout_constraintHorizontal_chainStyle="packed" | |||
<androidx.constraintlayout.widget.ConstraintLayout | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/title_bar_height" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
app:layout_goneMarginEnd="66dp" /> | |||
app:layout_constraintTop_toTopOf="parent"> | |||
<TextView | |||
android:id="@+id/tv_num_progress" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="2dp" | |||
android:layout_marginEnd="70dp" | |||
tools:text="90/100" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
android:textStyle="bold" | |||
android:visibility="visible" | |||
app:layout_constrainedWidth="true" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toEndOf="@id/tv_title" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
<ImageView | |||
android:id="@+id/img_back" | |||
android:layout_width="wrap_content" | |||
android:layout_height="match_parent" | |||
android:layout_centerVertical="true" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:scaleType="centerInside" | |||
android:src="@drawable/ic_back" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
<TextView | |||
android:id="@+id/tv_title" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="70dp" | |||
android:ellipsize="end" | |||
android:maxLines="1" | |||
tools:text="小学" | |||
android:gravity="center" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/bigSize" | |||
android:textStyle="bold" | |||
app:layout_constrainedWidth="true" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toStartOf="@+id/tv_num_progress" | |||
app:layout_constraintHorizontal_chainStyle="packed" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
app:layout_goneMarginEnd="70dp" /> | |||
<com.xkl.cdl.widget.VoiceSwitch | |||
android:id="@+id/voice_switch" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:paddingEnd="@dimen/global_spacing" | |||
android:visibility="visible" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
</androidx.constraintlayout.widget.ConstraintLayout> | |||
<TextView | |||
android:id="@+id/tv_num_progress" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="2dp" | |||
android:layout_marginEnd="70dp" | |||
tools:text="90/100" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
android:textStyle="bold" | |||
android:visibility="@{showProgress?View.VISIBLE:View.GONE}" | |||
app:layout_constrainedWidth="true" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toEndOf="@id/tv_title" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:visibility="gone"/> | |||
<com.xkl.cdl.widget.VoiceSwitch | |||
android:id="@+id/voice_switch" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:visibility="visible" | |||
android:layout_marginEnd="@dimen/global_spacing" | |||
app:layout_constraintBottom_toBottomOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
</androidx.constraintlayout.widget.ConstraintLayout> | |||
</layout> |
@@ -0,0 +1,100 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:app="http://schemas.android.com/apk/res-auto" | |||
xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:tools="http://schemas.android.com/tools" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
> | |||
<!-- tools:showIn="@layout/activity_learn_word"--> | |||
<com.airbnb.lottie.LottieAnimationView | |||
android:id="@+id/iv_voice" | |||
android:layout_width="74dp" | |||
android:layout_height="74dp" | |||
app:lottie_fileName="data.json" | |||
app:lottie_loop="true" | |||
app:lottie_autoPlay="false" | |||
app:lottie_repeatMode="restart" | |||
app:layout_constraintLeft_toLeftOf="parent" | |||
app:layout_constraintRight_toRightOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
app:layout_constraintBottom_toBottomOf="parent" /> | |||
<!--图片--> | |||
<com.google.android.material.imageview.ShapeableImageView | |||
android:id="@+id/img_word" | |||
android:layout_width="75dp" | |||
android:layout_height="75dp" | |||
android:layout_marginTop="12dp" | |||
android:scaleType="centerInside" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
app:shapeAppearance="@style/roundedCornerStyle" | |||
tools:src="@mipmap/img_default" /> | |||
<include | |||
android:id="@+id/inc_word" | |||
layout="@layout/inc_word" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/height_word" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/img_word" /> | |||
<TextView | |||
android:id="@+id/tv_phonetic" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
android:layout_marginTop="10dp" | |||
android:gravity="center" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingRight="@dimen/global_spacing" | |||
android:textColor="@color/gray_2" | |||
android:textSize="@dimen/smallerSize" | |||
app:layout_constraintTop_toBottomOf="@+id/inc_word" | |||
tools:text="英 [gud:bai] 美 [gud:bai] " /> | |||
<TextView | |||
android:id="@+id/tv_explain" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginTop="10dp" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_phonetic" | |||
tools:text="基本释义" /> | |||
<TextView | |||
android:id="@+id/tv_expand_explain" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginTop="8dp" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
android:textColor="@color/gray_2" | |||
android:textSize="@dimen/smallSize" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_explain" | |||
tools:text="扩展释义>" /> | |||
<TextView | |||
android:id="@+id/tv_pattern" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
android:layout_marginTop="8dp" | |||
android:textColor="@color/gray_2" | |||
android:textSize="@dimen/smallSize" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_expand_explain" | |||
tools:text="句型>" /> | |||
</androidx.constraintlayout.widget.ConstraintLayout> |
@@ -0,0 +1,22 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.appcompat.widget.AppCompatTextView 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:id="@+id/tv_word" | |||
android:layout_width="0dp" | |||
android:layout_height="@dimen/height_word" | |||
android:layout_marginTop="10dp" | |||
android:gravity="center" | |||
android:paddingStart="10dp" | |||
android:paddingEnd="10dp" | |||
android:textColor="@color/num0" | |||
android:textSize="@dimen/size_max_word" | |||
app:autoSizeMaxTextSize="@dimen/size_max_word" | |||
app:autoSizeMinTextSize="@dimen/miniSize" | |||
app:autoSizeStepGranularity="1dp" | |||
app:autoSizeTextType="uniform" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" | |||
tools:showIn="@layout/inc_exam_word_choose_content" | |||
tools:text="gradual" /> |
@@ -0,0 +1,110 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<androidx.core.widget.NestedScrollView xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:app="http://schemas.android.com/apk/res-auto" | |||
android:id="@+id/scrollview" | |||
android:layout_width="match_parent" | |||
android:layout_height="match_parent" | |||
xmlns:tools="http://schemas.android.com/tools"> | |||
<androidx.constraintlayout.widget.ConstraintLayout | |||
android:layout_width="match_parent" | |||
android:layout_height="match_parent"> | |||
<View | |||
android:id="@+id/v_space" | |||
android:layout_width="match_parent" | |||
android:layout_height="@dimen/line_height" | |||
android:background="@color/gray_1" | |||
app:layout_constraintEnd_toEndOf="parent" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toTopOf="parent" /> | |||
<TextView | |||
android:id="@+id/tv_phrase_flag" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginTop="8dp" | |||
android:drawablePadding="8dp" | |||
android:gravity="center_vertical" | |||
android:text="@string/phrase" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
android:textStyle="bold" | |||
app:drawableStartCompat="@drawable/detail_phrase_flag" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/v_space"/> | |||
<com.suliang.common.widget.TagLinearLayout | |||
android:id="@+id/layout_phrase" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
android:paddingStart="@dimen/global_spacing" | |||
android:paddingEnd="@dimen/global_spacing" | |||
app:item_horizontal_space="20dp" | |||
app:item_vertical_space="2dp" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_phrase_flag"> | |||
</com.suliang.common.widget.TagLinearLayout> | |||
<TextView | |||
android:id="@+id/tv_example_flag" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginTop="8dp" | |||
android:drawablePadding="8dp" | |||
android:gravity="center_vertical" | |||
android:text="@string/example" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
android:textStyle="bold" | |||
app:drawableStartCompat="@drawable/detail_example_flag" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/layout_phrase"/> | |||
<TextView | |||
android:id="@+id/tv_example" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginEnd="@dimen/global_spacing" | |||
android:gravity="center_vertical" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/smallSize" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_example_flag" | |||
tools:text="例句"/> | |||
<TextView | |||
android:id="@+id/tv_reference_flag" | |||
android:layout_width="wrap_content" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginTop="8dp" | |||
android:drawablePadding="8dp" | |||
android:gravity="center_vertical" | |||
android:text="@string/reference" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/normalSize" | |||
android:textStyle="bold" | |||
app:drawableStartCompat="@drawable/detail_reference_flag" | |||
app:layout_constraintStart_toStartOf="parent" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_example"/> | |||
<TextView | |||
android:id="@+id/tv_reference" | |||
tools:text="参考内容" | |||
android:layout_width="match_parent" | |||
android:layout_height="wrap_content" | |||
android:layout_marginStart="@dimen/global_spacing" | |||
android:layout_marginEnd="@dimen/global_spacing" | |||
android:gravity="center_vertical" | |||
android:textColor="@color/main_text_color" | |||
android:textSize="@dimen/smallSize" | |||
app:layout_constraintTop_toBottomOf="@+id/tv_reference_flag"/> | |||
</androidx.constraintlayout.widget.ConstraintLayout> | |||
</androidx.core.widget.NestedScrollView> |
@@ -0,0 +1,25 @@ | |||
<?xml version="1.0" encoding="utf-8"?> | |||
<layout xmlns:android="http://schemas.android.com/apk/res/android" | |||
xmlns:tools="http://schemas.android.com/tools" | |||
xmlns:app="http://schemas.android.com/apk/res-auto"> | |||
<LinearLayout | |||
android:layout_width="wrap_content" | |||
android:layout_height="match_parent" | |||
android:orientation="vertical" | |||
android:paddingTop="4dp" | |||
android:gravity="bottom"> | |||
<TextView | |||
android:id="@+id/tv_history" | |||
android:layout_width="wrap_content" | |||
android:layout_height="match_parent" | |||
android:gravity="center" | |||
android:paddingLeft="4dp" | |||
android:paddingRight="4dp" | |||
android:textSize="@dimen/smallerSize" | |||
android:maxLines="1" | |||
android:text="hello" | |||
tools:background="@drawable/shape_rounder_toplr_8_white"/> | |||
</LinearLayout> | |||
</layout> |
@@ -31,6 +31,10 @@ | |||
<color name="red_3">#FF0000</color> | |||
<color name="control_left">#687A69</color> | |||
<color name="control_center">#85766D</color> | |||
<color name="control_right">#666D80</color> | |||
<color name="num0">#E50213</color> | |||
<color name="num1">#E50251</color> |
@@ -42,12 +42,7 @@ | |||
<string name="continue_learn">继续学习</string> | |||
<string name="test_again">再测一次</string> | |||
<string name="test_type_after_total">学后总测试</string> | |||
<string name="title_activity_learn_base">LearnBaseActivity</string> | |||
<!-- Strings used for fragments for navigation --> | |||
<string name="first_fragment_label">First Fragment</string> | |||
<string name="second_fragment_label">Second Fragment</string> | |||
<string name="next">Next</string> | |||
<string name="previous">Previous</string> | |||
<string name="hello_first_fragment">Hello first fragment</string> | |||
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string> | |||
@@ -69,4 +64,14 @@ | |||
<string name="lesson_relearn_content">但不会清空测试与备忘本数据</string> | |||
<string name="sure">确定</string> | |||
<string name="control_answer">答案</string> | |||
<string name="control_correct">正确</string> | |||
<string name="control_error">错误/不认识</string> | |||
<string name="control_reRead">重读</string> | |||
<string name="control_next">下一条</string> | |||
<string name="phrase">词组</string> | |||
<string name="example">例句</string> | |||
<string name="reference">参考</string> | |||
<string name="auto_playing">自动播放中···</string> | |||
</resources> |
@@ -23,6 +23,17 @@ | |||
<item name="android:layout_marginTop">66dp</item> | |||
<item name="android:backgroundTint">@color/theme_color</item> | |||
</style> | |||
<!--只有button的属性,没有布局的属性--> | |||
<style name="common_button" parent="Widget.MaterialComponents.Button.UnelevatedButton"> | |||
<item name="android:layout_width">0dp</item> | |||
<item name="android:layout_height">@dimen/common_button_height</item> | |||
<item name="android:gravity">center</item> | |||
<item name="android:insetTop">0dp</item> | |||
<item name="android:insetBottom">0dp</item> | |||
<item name="android:textSize">@dimen/smallSize</item> | |||
<item name="android:textColor">@color/white</item> | |||
<item name="android:backgroundTint">@color/theme_color</item> | |||
</style> | |||
<!--dialog style --> | |||
<style name="dialog_style" parent="@android:style/Theme.Dialog"> |
@@ -0,0 +1,12 @@ | |||
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||
android:width="16dp" | |||
android:height="16dp" | |||
android:viewportWidth="16" | |||
android:viewportHeight="16"> | |||
<path | |||
android:pathData="M12.5708,8.8575L5.5145,13.0913C5.0409,13.3755 4.4267,13.2219 4.1425,12.7483C4.0493,12.5929 4,12.4151 4,12.2338L4,3.7662C4,3.2139 4.4477,2.7662 5,2.7662C5.1812,2.7662 5.3591,2.8154 5.5145,2.9087L12.5708,7.1425C13.0444,7.4267 13.198,8.0409 12.9138,8.5145C12.8294,8.6552 12.7116,8.773 12.5708,8.8575Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
</vector> |
@@ -0,0 +1,12 @@ | |||
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||
android:width="16dp" | |||
android:height="16dp" | |||
android:viewportWidth="16" | |||
android:viewportHeight="16"> | |||
<path | |||
android:pathData="M5,3C5.5523,3 6,3.4477 6,4L6,12C6,12.5523 5.5523,13 5,13C4.4477,13 4,12.5523 4,12L4,4C4,3.4477 4.4477,3 5,3ZM12,3C12.5523,3 13,3.4477 13,4L13,12C13,12.5523 12.5523,13 12,13C11.4477,13 11,12.5523 11,12L11,4C11,3.4477 11.4477,3 12,3Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
</vector> |
@@ -0,0 +1,74 @@ | |||
<vector xmlns:android="http://schemas.android.com/apk/res/android" | |||
android:width="16dp" | |||
android:height="16dp" | |||
android:viewportWidth="16" | |||
android:viewportHeight="16"> | |||
<path | |||
android:pathData="M-283,-755h375v812h-375z" | |||
android:strokeWidth="1" | |||
android:fillColor="#FFFFFF" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M4,3L12,3C12.5523,3 13,3.4477 13,4L13,12C13,12.5523 12.5523,13 12,13L4,13C3.4477,13 3,12.5523 3,12L3,4C3,3.4477 3.4477,3 4,3Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M-4,-3L72,-3A4,4 0,0 1,76 1L76,15A4,4 0,0 1,72 19L-4,19A4,4 0,0 1,-8 15L-8,1A4,4 0,0 1,-4 -3z" | |||
android:strokeLineJoin="round" | |||
android:strokeWidth="1" | |||
android:fillColor="#00000000" | |||
android:strokeColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeLineCap="round"/> | |||
<path | |||
android:pathData="M-263,-3L-187,-3A4,4 0,0 1,-183 1L-183,15A4,4 0,0 1,-187 19L-263,19A4,4 0,0 1,-267 15L-267,1A4,4 0,0 1,-263 -3z" | |||
android:strokeLineJoin="round" | |||
android:strokeWidth="1" | |||
android:fillColor="#00000000" | |||
android:strokeColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeLineCap="round"/> | |||
<path | |||
android:pathData="M-246.4292,8.8575L-253.4855,13.0913C-253.9591,13.3755 -254.5733,13.2219 -254.8575,12.7483C-254.9507,12.5929 -255,12.4151 -255,12.2338L-255,3.7662C-255,3.2139 -254.5523,2.7662 -254,2.7662C-253.8188,2.7662 -253.6409,2.8154 -253.4855,2.9087L-246.4292,7.1425C-245.9556,7.4267 -245.802,8.0409 -246.0862,8.5145C-246.1706,8.6552 -246.2884,8.773 -246.4292,8.8575Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M4,3L12,3C12.5523,3 13,3.4477 13,4L13,12C13,12.5523 12.5523,13 12,13L4,13C3.4477,13 3,12.5523 3,12L3,4C3,3.4477 3.4477,3 4,3Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M-4,-3L72,-3A4,4 0,0 1,76 1L76,15A4,4 0,0 1,72 19L-4,19A4,4 0,0 1,-8 15L-8,1A4,4 0,0 1,-4 -3z" | |||
android:strokeLineJoin="round" | |||
android:strokeWidth="1" | |||
android:fillColor="#00000000" | |||
android:strokeColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeLineCap="round"/> | |||
<path | |||
android:pathData="M4,3L12,3C12.5523,3 13,3.4477 13,4L13,12C13,12.5523 12.5523,13 12,13L4,13C3.4477,13 3,12.5523 3,12L3,4C3,3.4477 3.4477,3 4,3Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M4,3L12,3C12.5523,3 13,3.4477 13,4L13,12C13,12.5523 12.5523,13 12,13L4,13C3.4477,13 3,12.5523 3,12L3,4C3,3.4477 3.4477,3 4,3Z" | |||
android:strokeWidth="1" | |||
android:fillColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeColor="#00000000"/> | |||
<path | |||
android:pathData="M-4,-3L72,-3A4,4 0,0 1,76 1L76,15A4,4 0,0 1,72 19L-4,19A4,4 0,0 1,-8 15L-8,1A4,4 0,0 1,-4 -3z" | |||
android:strokeLineJoin="round" | |||
android:strokeWidth="1" | |||
android:fillColor="#00000000" | |||
android:strokeColor="#5082E6" | |||
android:fillType="evenOdd" | |||
android:strokeLineCap="round"/> | |||
</vector> |
@@ -27,7 +27,7 @@ ext { | |||
min_sdk_version : 21, | |||
target_sdk_version : 31, | |||
version_code : 100, | |||
version_name : "100", | |||
version_name : "1.0.0", | |||
applicationId : "com.xkl.cdl" | |||
] | |||
versions = [ |
@@ -105,20 +105,13 @@ abstract class BaseRVAdapter<T> : | |||
notifyDataSetChanged() | |||
} | |||
/** | |||
* 添加单条数据 | |||
* @param data T? | |||
* @param position Int? | |||
*/ | |||
fun addData(data: T?, position: Int?) { | |||
open fun addData(data: T?, position: Int?) { | |||
data?.let { | |||
val size = mData.size | |||
val startPosition = position?.let { it -> | |||
@@ -157,6 +150,12 @@ abstract class BaseRVAdapter<T> : | |||
} | |||
} | |||
fun removeData(position:Int){ | |||
if(mData.size >= position){ | |||
mData.removeAt(position) | |||
notifyItemRangeChanged(position,mData.size-position) | |||
} | |||
} | |||
@@ -0,0 +1,25 @@ | |||
package com.suliang.common.util | |||
/** | |||
* author suliang | |||
* create 2022/4/25 16:29 | |||
* Describe: | |||
*/ | |||
class ColorUtil { | |||
companion object{ | |||
/** | |||
* 把一个int颜色值转换成String | |||
* @param color | |||
* @return | |||
*/ | |||
fun getHexWebString(color : Int) : String { | |||
var s = "#" | |||
val colorStr = color and -0x1000000 or (color and 0x00ff0000) or (color and 0x0000ff00) or (color and 0x000000ff) | |||
var s1 = Integer.toHexString(colorStr) | |||
s1 = s1.substring(2, s1.length) | |||
s = s + s1 | |||
return s | |||
} | |||
} | |||
} |
@@ -1,8 +1,82 @@ | |||
package com.suliang.common.util | |||
import android.text.Html | |||
import android.text.Spanned | |||
import androidx.annotation.ColorInt | |||
import java.util.regex.Pattern | |||
/** | |||
* author suliang | |||
* create 2022/4/11 17:16 | |||
* Describe: | |||
*/class StringUtil { | |||
* author suliang | |||
* create 2022/4/11 17:16 | |||
* Describe: | |||
*/ | |||
class StringUtil { | |||
companion object { | |||
/** | |||
* 识字课程认读显示转换: (你)好,括号中的字变大,并设置颜色 | |||
* @param word 处理的文字 | |||
* @param colorId 处理的颜色id color.xml | |||
* @return | |||
*/ | |||
fun literacyToHtmlWord(word : String, @ColorInt colorId : Int) : Spanned? { | |||
val m = Pattern.compile("\\([\u4e00-\u9fa5]\\)").matcher(word) | |||
val builder = StringBuffer() | |||
val color : String = ColorUtil.getHexWebString(colorId) | |||
var isFind = false | |||
var previousEndPosition = 0 //下次循环开始的位置 | |||
while (m.find()) { | |||
isFind = true | |||
val startPosition = m.start() //左括号的下一位置 | |||
val endPosition = m.end() //右括号位置 | |||
if (startPosition - previousEndPosition > 0) { | |||
builder.append("<font color=\"#FF323233\">").append(word.substring(previousEndPosition, startPosition)) | |||
.append("</font>") | |||
} | |||
//直接匹配添加 | |||
builder.append("<font color= \"").append(color).append("\"><big><big>") | |||
.append(word.substring(startPosition + 1, endPosition - 1)).append("</big></big></font>") | |||
previousEndPosition = endPosition | |||
} | |||
if (isFind) { | |||
if (previousEndPosition != word.length) { | |||
builder.append("<font color=\"#FF323233\">").append(word.substring(previousEndPosition)).append("</font>") | |||
} | |||
} else { | |||
builder.append("<font color=\"").append(color).append("\">").append(word).append("</font>") | |||
} | |||
println(builder.toString()) | |||
return Html.fromHtml(builder.toString()) | |||
} | |||
/** | |||
* 识字课程,获取括号包裹的中文内容 (你)好 --> 你 | |||
* @param word 识字的词语 | |||
* @return 英文括号中的内容 | |||
*/ | |||
fun literacyGetWord(word : String) : String { | |||
val m = Pattern.compile("\\([\u4e00-\u9fa5]\\)").matcher(word) | |||
return if (m.find()) { | |||
word.substring(m.start() + 1, m.end() - 1) | |||
} else word | |||
} | |||
/** 识字课程,备忘本使用,去掉括号包裹内容的中文括号 */ | |||
fun literacyGetMemoWord(word : String) : String { | |||
val m = Pattern.compile("\\([\u4e00-\u9fa5]\\)").matcher(word) | |||
val buffer = StringBuffer() | |||
while (m.find()) { | |||
val startPosition = m.start() //左括号的下一位置 | |||
val endPosition = m.end() //右括号位置 | |||
m.appendReplacement(buffer, word.substring(startPosition + 1, endPosition - 1)) | |||
} | |||
m.appendTail(buffer) | |||
return buffer.toString() | |||
} | |||
} | |||
} |
@@ -6,6 +6,7 @@ import android.content.Context | |||
import android.content.res.Resources | |||
import android.os.Build | |||
import android.util.DisplayMetrics | |||
import android.util.TypedValue | |||
import android.view.ViewConfiguration | |||
import android.view.WindowManager | |||
import com.suliang.common.util.AppGlobals | |||
@@ -115,9 +116,14 @@ object ScreenUtil { | |||
/** | |||
* dp2px | |||
*/ | |||
fun dp2px(dpValue: Float): Int { | |||
val scale = AppGlobals.application.resources.displayMetrics.density | |||
return (dpValue * scale + 0.5f).toInt() | |||
fun dp2px(dpValue: Float): Float { | |||
// 参数1:输入的value类型 | |||
// 参数2:要转换的数值 | |||
// 参数3:Resources.getSystem().displayMetrics(很多人用的是Context.displayMetrics,需要把context传递过来,这里可以用Resources.getSystem方法会更好) | |||
return TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,dpValue,Resources.getSystem().displayMetrics) | |||
// val scale = AppGlobals.application.resources.displayMetrics.density | |||
// return (dpValue * scale + 0.5f).toInt() | |||
} | |||
/** |
@@ -0,0 +1,169 @@ | |||
package com.suliang.common.widget; | |||
import android.content.Context; | |||
import android.content.res.TypedArray; | |||
import android.util.AttributeSet; | |||
import android.view.View; | |||
import android.widget.LinearLayout; | |||
import androidx.annotation.Nullable; | |||
import androidx.constraintlayout.widget.ConstraintLayout; | |||
import com.suliang.common.R; | |||
import java.util.ArrayList; | |||
import java.util.List; | |||
/** | |||
* author suliang | |||
* create 2021/12/31 12:45 | |||
* Describe: 自适应的流式布局 ,子控件一行放不下的情况下,需要换行为两行,子控件不需要设置margin | |||
* 使用方式: 定义布局,width = “match_parent" or 固定值 ,height = "wrap_content" 可设置左右的内间距 | |||
* 子控件: 不设置margin,width 和 height 均使用wrap_content | |||
* 每一行的第一个控件与父控件没有间隔,即不添加 itemHorizontalSpace。当前行的第二个控件开始与前一个控件间隔 itemHorizontalSpace | |||
* 第一行的第一个控件与父控件没有间隔,即不添加 itemVerticalSpace ,第二行后与前一项的才添加itemVerticalSpace | |||
* 整体布局相当于: | |||
* leftPadding View1 itemHorizontalSpace View2 rightPadding | |||
* itemVerticalSpace | |||
* leftPadding View3 itemHorizontalSpace View4 rightPadding | |||
*/ | |||
public class TagLinearLayout extends LinearLayout { | |||
private final int itemVerticalSpace; //垂直方向的控件间距, 默认12px | |||
private final int itemHorizontalSpace; //横置方向的控件间距,默认12px | |||
private final List<List<View>> allView = new ArrayList<>() ; //所有控件每一行的集合和一行中有几个View的集合 | |||
private final List<Integer> lineHeights = new ArrayList<>() ; //每一行的最高控件的高度 | |||
private boolean needLayout = true ; | |||
public TagLinearLayout(Context context) { | |||
this(context,null); | |||
} | |||
public TagLinearLayout(Context context, @Nullable AttributeSet attrs) { | |||
this(context, attrs,0); | |||
} | |||
public TagLinearLayout(Context context, @Nullable AttributeSet attrs, int defStyleAttr) { | |||
super(context, attrs, defStyleAttr); | |||
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.TagLinearLayout); | |||
itemVerticalSpace = (int) typedArray.getDimension(R.styleable.TagLinearLayout_item_vertical_space, 12); | |||
itemHorizontalSpace = (int) typedArray.getDimension(R.styleable.TagLinearLayout_item_horizontal_space, 12); | |||
typedArray.recycle(); | |||
} | |||
@Override | |||
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | |||
allView.clear(); | |||
lineHeights.clear(); | |||
//控件宽度 | |||
int width = MeasureSpec.getSize(widthMeasureSpec); | |||
measureChildren(widthMeasureSpec,heightMeasureSpec); | |||
//父控件横向和垂直的间距 | |||
int horizontalPadding = getPaddingLeft() + getPaddingRight(); | |||
int verticalPadding = getPaddingTop() + getPaddingBottom(); | |||
//用于计算的父控件宽度 | |||
int widthNotHavePadding = width - horizontalPadding; | |||
int childWidth ; //当前行 宽度 | |||
int childHeight ; //当前行 高度 | |||
int lineTotalWidth = 0 ; //当前行 总宽度 | |||
int lineMaxHeight = 0 ; //当前行 最大高度 | |||
int totalHeight = 0 ; //记录总高度 | |||
int line = 0 ; //总行数 | |||
int childCount = getChildCount(); | |||
//一行的内容 | |||
List<View> lineViews = null ; | |||
for (int i = 0 ; i < childCount ; i++){ | |||
View child = getChildAt(i); | |||
//子控件的宽 = 自生宽 ,子控件布局为 wrap_content | |||
childWidth = child.getMeasuredWidth(); | |||
childHeight = child.getMeasuredHeight(); | |||
if (lineViews != null && lineViews.size() != 0 && lineTotalWidth + childWidth + itemHorizontalSpace <= widthNotHavePadding){ //非当前行的第一个控件 | |||
lineMaxHeight = Math.max(lineMaxHeight,childHeight); | |||
lineTotalWidth += (childWidth+itemHorizontalSpace); | |||
}else{ //当前行的第一个控件,即新行开始 | |||
//行数加1 | |||
line++; | |||
//累加总高 | |||
//1、只有一行,则会在最后一个item进行累加 | |||
//2、有多行,则在下一行开始时累加上一行的高,最后一行在最后一个的时候进行累加 | |||
if ( line > 1 ){ | |||
totalHeight += lineMaxHeight ; | |||
lineHeights.add(lineMaxHeight); | |||
} | |||
//当前行基础值 | |||
lineTotalWidth = childWidth ; | |||
lineMaxHeight = childHeight ; | |||
//赋值处理 | |||
lineViews = new ArrayList<>(); //赋值新行集合 | |||
allView.add(lineViews); //添加到总集合 | |||
} | |||
//最后一行,添加总高 | |||
if (i == childCount -1){ | |||
totalHeight += lineMaxHeight ; | |||
lineHeights.add(lineMaxHeight); | |||
} | |||
//添加到行集合 | |||
lineViews.add(child); | |||
} | |||
//总高 = 高度 + 内间距 + 行间距 | |||
//控件高度 | |||
int height = totalHeight + verticalPadding; | |||
if (line > 1){ | |||
height = height + (line -1) * itemVerticalSpace ; | |||
} | |||
//如果设置了最小高度,则判断设置 | |||
if (this.getVisibility() != View.GONE ){ | |||
if (getParent() instanceof ConstraintLayout){ | |||
ConstraintLayout.LayoutParams params = (ConstraintLayout.LayoutParams) getLayoutParams(); | |||
height = Math.max(height,params.matchConstraintMinHeight); | |||
}else{ | |||
height = Math.max(height,getMinimumHeight()); | |||
} | |||
} | |||
//设值 | |||
setMeasuredDimension(width,Math.max(height,getMinimumHeight())); | |||
} | |||
@Override | |||
protected void onLayout(boolean changed, int l, int t, int r, int b) { | |||
// super.onLayout(changed, l, t, r, b); | |||
if (needLayout || changed){ | |||
needLayout = false ; | |||
} | |||
int top = getPaddingTop(); | |||
int left = getPaddingLeft(); | |||
int right ; | |||
int bottom ; | |||
//循环行 | |||
for (int i = 0 , lines = allView.size(); i < lines ; i++){ | |||
//当前行 | |||
List<View> lineViews = allView.get(i); | |||
int currentLineMaxHeight = lineHeights.get(i); | |||
for (int j = 0 , count = lineViews.size() ; j < count ; j++ ){ | |||
View view = lineViews.get(j); | |||
int measuredWidth = view.getMeasuredWidth(); | |||
int measuredHeight = view.getMeasuredHeight(); | |||
int currentTop = (currentLineMaxHeight - measuredHeight)/2 + top ; | |||
bottom = currentTop + measuredHeight; | |||
right = left + measuredWidth; | |||
view.layout(left,currentTop,right,bottom); | |||
//重置left | |||
left = right + itemHorizontalSpace; | |||
} | |||
//新行 | |||
top = top + lineHeights.get(i) + itemVerticalSpace; | |||
left = getPaddingLeft(); | |||
} | |||
} | |||
} |
@@ -39,7 +39,7 @@ class TitleBar @JvmOverloads constructor(context: Context, attrs: AttributeSet? | |||
context.obtainStyledAttributes(attrs, R.styleable.TitleBar).run { | |||
val barBackground = getColor(R.styleable.TitleBar_barBackground, 0) | |||
val titleTextValue = getString(R.styleable.TitleBar_titleTextValue) | |||
val titleTextSize = getDimension(R.styleable.TitleBar_titleTextSize, ScreenUtil.dp2px(18f).toFloat()) | |||
val titleTextSize = getDimension(R.styleable.TitleBar_titleTextSize, ScreenUtil.dp2px(18f)) | |||
val titleTextColor = getColor(R.styleable.TitleBar_titleTextColor, Color.parseColor("#323232")) | |||
val rightTextValue = getString(R.styleable.TitleBar_rightTextValue) | |||
val rightTextColor = getColor(R.styleable.TitleBar_rightTextColor, 0) |
@@ -25,7 +25,11 @@ | |||
<attr name="backTextColor" format="color"/> <!--左侧大小--> | |||
<attr name="backSrc" format="reference|integer"/> <!--左侧图片--> | |||
<attr name="drawPadding" format="dimension"/> <!--图片drawPadding--> | |||
</declare-styleable> | |||
<!--自定义标签容器--> | |||
<declare-styleable name="TagLinearLayout"> | |||
<attr name="item_vertical_space" format="dimension"/> <!--垂直方向的控件间距--> | |||
<attr name="item_horizontal_space" format="dimension"/> <!--横向方向的控件间距--> | |||
</declare-styleable> | |||
</resources> |