Browse Source

部分学习功能

master
suliang 2 years ago
parent
commit
fff083c270
45 changed files with 2002 additions and 225 deletions
  1. 17
    3
      .idea/misc.xml
  2. 61
    0
      app/src/main/java/com/xkl/cdl/Extension.kt
  3. 187
    0
      app/src/main/java/com/xkl/cdl/adapter/AdapterHistoricalRoute.kt
  4. 1
    1
      app/src/main/java/com/xkl/cdl/adapter/itemdecoration/SpellItemDecoration.kt
  5. 1
    1
      app/src/main/java/com/xkl/cdl/data/AppConstants.kt
  6. 2
    2
      app/src/main/java/com/xkl/cdl/data/bean/BaseWord.kt
  7. 1
    1
      app/src/main/java/com/xkl/cdl/data/bean/LearnWord.kt
  8. 65
    4
      app/src/main/java/com/xkl/cdl/data/manager/db/DBCourseManager.kt
  9. 12
    12
      app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt
  10. 202
    5
      app/src/main/java/com/xkl/cdl/module/learn/LearnWordActivity.kt
  11. 22
    0
      app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt
  12. 20
    4
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseLessonFragment.kt
  13. 2
    3
      app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragmentViewModel.kt
  14. 309
    63
      app/src/main/java/com/xkl/cdl/util/LearnRuleUtil.kt
  15. 1
    1
      app/src/main/java/com/xkl/cdl/widget/MyRankingView.java
  16. 1
    1
      app/src/main/java/com/xkl/cdl/widget/smartRefresh/XkLRefreshHeader.kt
  17. 8
    0
      app/src/main/res/drawable/detail_example_flag.xml
  18. 8
    0
      app/src/main/res/drawable/detail_phrase_flag.xml
  19. 8
    0
      app/src/main/res/drawable/detail_reference_flag.xml
  20. 6
    0
      app/src/main/res/drawable/shape_rounder_toplr_8_white.xml
  21. 3
    1
      app/src/main/res/layout/activity_learn_exam.xml
  22. 152
    6
      app/src/main/res/layout/activity_learn_word.xml
  23. 58
    0
      app/src/main/res/layout/inc_control_button.xml
  24. 29
    15
      app/src/main/res/layout/inc_exam_spell_content.xml
  25. 4
    17
      app/src/main/res/layout/inc_exam_word_choose_content.xml
  26. 73
    0
      app/src/main/res/layout/inc_learn_spell.xml
  27. 72
    60
      app/src/main/res/layout/inc_learn_title.xml
  28. 100
    0
      app/src/main/res/layout/inc_learn_word.xml
  29. 22
    0
      app/src/main/res/layout/inc_word.xml
  30. 110
    0
      app/src/main/res/layout/inc_word_detail.xml
  31. 25
    0
      app/src/main/res/layout/item_historical_route.xml
  32. 4
    0
      app/src/main/res/values/colors.xml
  33. 11
    6
      app/src/main/res/values/strings.xml
  34. 11
    0
      app/src/main/res/values/styles.xml
  35. 12
    0
      app/svg/drawable/ic_play.xml
  36. 12
    0
      app/svg/drawable/ic_play_pause.xml
  37. 74
    0
      app/svg/drawable/ic_play_stop.xml
  38. 1
    1
      build.gradle
  39. 8
    9
      lib/common/src/main/java/com/suliang/common/base/adapter/BaseRVAdapter.kt
  40. 25
    0
      lib/common/src/main/java/com/suliang/common/util/ColorUtil.kt
  41. 78
    4
      lib/common/src/main/java/com/suliang/common/util/StringUtil.kt
  42. 9
    3
      lib/common/src/main/java/com/suliang/common/util/os/ScreenUtil.kt
  43. 169
    0
      lib/common/src/main/java/com/suliang/common/widget/TagLinearLayout.java
  44. 1
    1
      lib/common/src/main/java/com/suliang/common/widget/TitleBar.kt
  45. 5
    1
      lib/common/src/main/res/values/attrs.xml

+ 17
- 3
.idea/misc.xml View File

<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_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_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/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/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/et_search_bg.xml" value="0.175" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_delete.xml" value="0.30520833333333336" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/ic_delete.xml" value="0.30520833333333336" />
<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/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/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_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_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_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/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/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" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/drawable/switch_thumb_selector.xml" value="0.3768518518518518" />
<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_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_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_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_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_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_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_main.xml" value="0.5" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/activity_splash.xml" value="0.4921875" />
<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_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_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/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_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_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_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/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_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" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/include_main_learn_center_course_type_title.xml" value="0.67" />
<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/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_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_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/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_course_progress.xml" value="0.25" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_coursepack.xml" value="0.43500866551126516" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/src/main/res/layout/main_item_coursepack.xml" value="0.43500866551126516" />
<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_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_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_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_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_spell.xml" value="0.5061538461538462" />
<entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_spoken.xml" value="0.5061538461538462" /> <entry key="..\:/Work/XKL/XKL/XklLocal/app/svg/drawable/ic_spoken.xml" value="0.5061538461538462" />

+ 61
- 0
app/src/main/java/com/xkl/cdl/Extension.kt View File

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
}
}

+ 187
- 0
app/src/main/java/com/xkl/cdl/adapter/AdapterHistoricalRoute.kt View File

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)
}
}

+ 1
- 1
app/src/main/java/com/xkl/cdl/adapter/itemdecoration/SpellItemDecoration.kt View File

*/ */
class SpellItemDecoration : ItemDecoration() { 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) { override fun getItemOffsets(outRect : Rect, view : View, parent : RecyclerView, state : RecyclerView.State) {
val chilidCount = parent.adapter!!.itemCount val chilidCount = parent.adapter!!.itemCount

+ 1
- 1
app/src/main/java/com/xkl/cdl/data/AppConstants.kt View File

const val COURSEPACK_TYPE_CHINESE_LITERACY = 3 const val COURSEPACK_TYPE_CHINESE_LITERACY = 3


/**课程包类型: categoryId -> 语文拼音 */ /**课程包类型: categoryId -> 语文拼音 */
const val COURSEPACK_TYPE_CHINESE_PINYIN = 1
const val COURSEPACK_TYPE_CHINESE_PINYIN = 5




/**课程类型: typeId 英语认读*/ /**课程类型: typeId 英语认读*/

+ 2
- 2
app/src/main/java/com/xkl/cdl/data/bean/BaseWord.kt View File

* @property courseType Int 课程类型 * @property courseType Int 课程类型
* @property chapterId Long 章节id * @property chapterId Long 章节id
* @property lessonId Long 课时id * @property lessonId Long 课时id
* @property wordId Long 内容id
* @property wordId Long 内容id 作文知识点时为"knowledge_id"
* @property first Boolean 是否第一次出现 * @property first Boolean 是否第一次出现
* @property reviewNum Int 大七次次数 * @property reviewNum Int 大七次次数
* @property reviewTime Long 复习时间 * @property reviewTime Long 复习时间
val chapterId: Long, val chapterId: Long,
val lessonId: Long, val lessonId: Long,
val wordId: Long, val wordId: Long,
val first: Boolean,
var first: Boolean,
val lessonType: Int) { val lessonType: Int) {
/** 大复习次数 */ /** 大复习次数 */
var reviewNum: Int = 0 var reviewNum: Int = 0

+ 1
- 1
app/src/main/java/com/xkl/cdl/data/bean/LearnWord.kt View File

lessonType) { lessonType) {




var word: String? = null //词汇
var word: String = "" //词汇
var phonetic_uk: String? = null // 英式音标 var phonetic_uk: String? = null // 英式音标
var phonetic_us: String? = null // 美式音标 var phonetic_us: String? = null // 美式音标
var phonetic_cn: String? = null // 中文拼音 var phonetic_cn: String? = null // 中文拼音

+ 65
- 4
app/src/main/java/com/xkl/cdl/data/manager/db/DBCourseManager.kt View File

import io.reactivex.rxjava3.annotations.NonNull import io.reactivex.rxjava3.annotations.NonNull
import net.sqlcipher.database.SQLiteDatabase import net.sqlcipher.database.SQLiteDatabase
import java.io.File import java.io.File
import java.lang.StringBuilder


/** /**
* author suliang * author suliang
} }
} }
/**
* 查询学习数据,结果为单词类型,其中作文知识点为单独查询
* @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)
}
}
/** /**
* 查询学习数据 * 查询学习数据
* @return List<LearnWord>? * @return List<LearnWord>?
*/ */
@SuppressLint("Range") @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>() val result = mutableListOf<LearnWord>()
open(dbcb) open(dbcb)
//从lesson已学位置开始获取数据 //从lesson已学位置开始获取数据
word = getString(getColumnIndex("word")) word = getString(getColumnIndex("word"))
basic_explanation = getString(getColumnIndex("basic_explaination")) basic_explanation = getString(getColumnIndex("basic_explaination"))
extend_explanation = getString(getColumnIndex("all_explaination")) extend_explanation = getString(getColumnIndex("all_explaination"))
phrase = getString(getColumnIndex("pharse"))
phrase = getString(getColumnIndex("phrase"))
example = getString(getColumnIndex("example")) example = getString(getColumnIndex("example"))
reference = getString(getColumnIndex("reference")) reference = getString(getColumnIndex("reference"))
return result 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? { fun queryPhoto(dbControlBase : DbControlBase, wordId : Long) : ByteArray? {
open(dbControlBase) open(dbControlBase)
var result : ByteArray? = null var result : ByteArray? = null
val sql = "SELECT photo FROM res WHERE word_id = $wordId" 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) result = getBlob(0)
} }
close() close()

+ 12
- 12
app/src/main/java/com/xkl/cdl/module/learn/LearnExamActivity.kt View File

AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> { AppConstants.COURSE_TYPE_ENGLISH_SPELL, AppConstants.COURSE_TYPE_CHINESE_COMPOSITION -> {
} }
else -> { else -> {
wordChooseBinding.tvWord.setOnClickListener(ivVoiceClick)
wordChooseBinding.incWord.tvWord.setOnClickListener(ivVoiceClick)
wordChooseBinding.ivVoice.setOnClickListener(ivVoiceClick) wordChooseBinding.ivVoice.setOnClickListener(ivVoiceClick)
} }
} }
//未答和正确都更新显示正确的项 错误同时显示正确和错误的项 //未答和正确都更新显示正确的项 错误同时显示正确和错误的项
wordChooseBinding.run { wordChooseBinding.run {
ivVoice.visibility = View.GONE ivVoice.visibility = View.GONE
tvWord.visibility = View.VISIBLE
incWord.tvWord.visibility = View.VISIBLE
//显示正确项 //显示正确项
vm.optionList[vm.currentCorrectPosition].run { vm.optionList[vm.currentCorrectPosition].run {
root.setBackgroundResource(vm.correctBg) root.setBackgroundResource(vm.correctBg)
} }
private fun initChooseUIData(examBean : ExamBean) { private fun initChooseUIData(examBean : ExamBean) {
wordChooseBinding.tvWord.text = examBean.word
wordChooseBinding.incWord.tvWord.text = examBean.word
wordChooseBinding.progressWordCountdownTime.run { wordChooseBinding.progressWordCountdownTime.run {
max = vm.currentMaxTime max = vm.currentMaxTime
progress = vm.currentMaxTime progress = vm.currentMaxTime
} }
private fun initVoiceUIData(examBean : ExamBean) { private fun initVoiceUIData(examBean : ExamBean) {
wordChooseBinding.tvWord.run {
wordChooseBinding.incWord.tvWord.run {
text = examBean.word text = examBean.word
visibility = View.GONE visibility = View.GONE
} }
} }
private fun initSpokenUIData(examBean : ExamBean) { private fun initSpokenUIData(examBean : ExamBean) {
wordChooseBinding.tvWord.text = examBean.word
wordChooseBinding.incWord.tvWord.text = examBean.word
if (examBean.questionIsAudio) { if (examBean.questionIsAudio) {
wordChooseBinding.tvWord.visibility = View.GONE
wordChooseBinding.incWord.tvWord.visibility = View.GONE
wordChooseBinding.ivVoice.visibility = View.VISIBLE wordChooseBinding.ivVoice.visibility = View.VISIBLE
} else { } else {
wordChooseBinding.tvWord.visibility = View.VISIBLE
wordChooseBinding.incWord.tvWord.visibility = View.VISIBLE
wordChooseBinding.ivVoice.visibility = View.GONE wordChooseBinding.ivVoice.visibility = View.GONE
} }
wordChooseBinding.progressWordCountdownTime.visibility = View.GONE wordChooseBinding.progressWordCountdownTime.visibility = View.GONE
private fun initSpellUIData(examBean : ExamBean) { private fun initSpellUIData(examBean : ExamBean) {
spellBinding.tvExplain.text = examBean.correct //释义 spellBinding.tvExplain.text = examBean.correct //释义
//初始显示word的时候,文字置空,颜色修改为黑色 //初始显示word的时候,文字置空,颜色修改为黑色
spellBinding.tvWord.run {
spellBinding.incWord.tvWord.run {
text = "" text = ""
setTextColor(ContextCompat.getColor(this@LearnExamActivity, R.color.main_text_color)) setTextColor(ContextCompat.getColor(this@LearnExamActivity, R.color.main_text_color))
} }
when { when {
isOver -> { //拼写结束 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) vm.spellOver(selectedValue.toString(), errorSize)
//执行当前的单词发音 延迟发音 //执行当前的单词发音 延迟发音
spellBinding.tvWord.postDelayed({ ivVoiceClick(spellBinding.tvWord) }, 200)
spellBinding.incWord.tvWord.postDelayed({ ivVoiceClick(spellBinding.incWord.tvWord) }, 200)
} }
else -> { else -> {
//设置为选中的值 //设置为选中的值
spellBinding.tvWord.text = selectedValue
spellBinding.incWord.tvWord.text = selectedValue
} }
} }
spellBinding.spellRecyclerView.scrollToPosition(nextPosition) spellBinding.spellRecyclerView.scrollToPosition(nextPosition)

+ 202
- 5
app/src/main/java/com/xkl/cdl/module/learn/LearnWordActivity.kt View File

package com.xkl.cdl.module.learn package com.xkl.cdl.module.learn


import androidx.appcompat.app.AppCompatActivity
import android.content.Context
import android.os.Bundle 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.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 -> ""
}
}
} }

+ 22
- 0
app/src/main/java/com/xkl/cdl/module/learn/LearnWordViewModel.kt View File

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


}

+ 20
- 4
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseLessonFragment.kt View File

import com.suliang.common.eventbus.LiveDataBus import com.suliang.common.eventbus.LiveDataBus
import com.xkl.cdl.adapter.AdapterLesson import com.xkl.cdl.adapter.AdapterLesson
import com.xkl.cdl.data.AppConstants 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.LearnDialogBean
import com.xkl.cdl.data.bean.course.ExamBean import com.xkl.cdl.data.bean.course.ExamBean
import com.xkl.cdl.data.bean.course.Lesson import com.xkl.cdl.data.bean.course.Lesson
import com.xkl.cdl.data.bean.intentdata.ExamData 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.event.LearnEventData
import com.xkl.cdl.data.manager.CourseManager import com.xkl.cdl.data.manager.CourseManager
import com.xkl.cdl.databinding.FragmentCourseLessonBinding import com.xkl.cdl.databinding.FragmentCourseLessonBinding
import com.xkl.cdl.dialog.LearnDialog import com.xkl.cdl.dialog.LearnDialog
import com.xkl.cdl.module.learn.LearnWordActivity


/** /**
* 课程章节目录 * 课程章节目录
private val onLessonClick : (v:View,position: Int, lesson: Lesson) -> Unit = { view, position, entity -> private val onLessonClick : (v:View,position: Int, lesson: Lesson) -> Unit = { view, position, entity ->
when(entity.lessonType){ when(entity.lessonType){
AppConstants.LESSON_TYPE_WORD -> { AppConstants.LESSON_TYPE_WORD -> {
if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做
startLearn(entity)
/* if (entity.beforeTestScore == AppConstants.NOT_DOING){ //课时学前测试,没有做
//弹窗显示学前测试提示 //弹窗显示学前测试提示
showLessonBeforeTestStartDialog(entity) showLessonBeforeTestStartDialog(entity)
}else if (!entity.learnIsOver){
}else if (!entity.learnIsOver){ //当前课时未学完,直接开始学习
startLearn(entity)
}else if (entity.afterTestScore != AppConstants.NOT_DOING){ }else if (entity.afterTestScore != AppConstants.NOT_DOING){
loadLessonAfterTest(entity) loadLessonAfterTest(entity)
}else{ //当前课时学习完成的弹窗 }else{ //当前课时学习完成的弹窗
showLessonAllOverDialog(entity) showLessonAllOverDialog(entity)
}
}*/
} }
AppConstants.LESSON_TYPE_SENTENCE -> { AppConstants.LESSON_TYPE_SENTENCE -> {


} }
} }
/**
* 查询课时数据,并开始学习,进入学习界面
* @param lesson Lesson 课时
*/
private fun startLearn(lesson : Lesson){
vm.loadLessonLearnData(lesson).observe(this){
DataTransferHolder.instance.putData(value = it)
startActivity(LearnWordActivity::class.java)
}
}
/** 开始课时学后测试 /** 开始课时学后测试
* 请求数据后,直接开始跳转 * 请求数据后,直接开始跳转
*/ */

+ 2
- 3
app/src/main/java/com/xkl/cdl/module/m_center_learn/coursechildren/CourseMainFragmentViewModel.kt View File

* @param lesson Lesson 课时 * @param lesson Lesson 课时
* @return MutableLiveData<LearnData> * @return MutableLiveData<LearnData>
*/ */
fun loadLessonLearnForWord(lesson : Lesson): MutableLiveData<LearnData>{
fun loadLessonLearnData(lesson : Lesson): MutableLiveData<LearnData>{
val result = MutableLiveData<LearnData>() val result = MutableLiveData<LearnData>()
Observable.create<List<LearnWord>> { Observable.create<List<LearnWord>> {
it.onNext(DBCourseManager.queryLearnDataForWord(dbControlBase, lesson))
it.onNext(DBCourseManager.queryLearnData(dbControlBase, lesson))
it.onComplete() it.onComplete()
}.compose(diskIo2Main()) }.compose(diskIo2Main())
.subscribe { .subscribe {
learnWordList = it learnWordList = it
} }
} }
return result return result
} }

+ 309
- 63
app/src/main/java/com/xkl/cdl/util/LearnRuleUtil.kt View File

package com.xkl.cdl.util package com.xkl.cdl.util


import com.xkl.cdl.data.bean.BaseWord import com.xkl.cdl.data.bean.BaseWord
import java.io.*
import java.util.*


/** /**
* author suliang * 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 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
}
} }

+ 1
- 1
app/src/main/java/com/xkl/cdl/widget/MyRankingView.java View File





private void initView() { private void initView() {
defaultSize = ScreenUtil.INSTANCE.dp2px(122); //默认大小
defaultSize = (int) ScreenUtil.INSTANCE.dp2px(122); //默认大小


mRectF = new RectF(); mRectF = new RectF();
if (normalColor != -2 && progressWidth != -2) { if (normalColor != -2 && progressWidth != -2) {

+ 1
- 1
app/src/main/java/com/xkl/cdl/widget/smartRefresh/XkLRefreshHeader.kt View File

init { init {
orientation = VERTICAL orientation = VERTICAL
gravity = Gravity.CENTER 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) LayoutInflater.from(context).inflate(R.layout.smart_refresh_header, this, true)
} }



+ 8
- 0
app/src/main/res/drawable/detail_example_flag.xml View File

<?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>

+ 8
- 0
app/src/main/res/drawable/detail_phrase_flag.xml View File

<?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>

+ 8
- 0
app/src/main/res/drawable/detail_reference_flag.xml View File

<?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>

+ 6
- 0
app/src/main/res/drawable/shape_rounder_toplr_8_white.xml View File

<?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>

+ 3
- 1
app/src/main/res/layout/activity_learn_exam.xml View File



<include <include
android:id="@+id/inc_learn_title" android:id="@+id/inc_learn_title"
layout="@layout/inc_learn_title" />
layout="@layout/inc_learn_title"
app:showProgress="@{true}"
/>


<include <include
android:id="@+id/inc_statistics" android:id="@+id/inc_statistics"

+ 152
- 6
app/src/main/res/layout/activity_learn_word.xml View File

<?xml version="1.0" encoding="utf-8"?> <?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: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>

+ 58
- 0
app/src/main/res/layout/inc_control_button.xml View File

<?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>

+ 29
- 15
app/src/main/res/layout/inc_exam_spell_content.xml View File

app:layout_constraintTop_toBottomOf="@+id/tv_explain" app:layout_constraintTop_toBottomOf="@+id/tv_explain"
tools:progress="20" /> 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_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_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="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 <TextView
android:id="@+id/tv_rule_tip" android:id="@+id/tv_rule_tip"
android:textSize="@dimen/smallerSize" android:textSize="@dimen/smallerSize"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_word" />
app:layout_constraintTop_toBottomOf="@+id/inc_word" />


<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/spell_recyclerView" android:id="@+id/spell_recyclerView"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@+id/tv_rule_tip" app:layout_constraintTop_toBottomOf="@+id/tv_rule_tip"
android:layout_marginTop="12dp" 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> </androidx.constraintlayout.widget.ConstraintLayout>

+ 4
- 17
app/src/main/res/layout/inc_exam_word_choose_content.xml View File

app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
android:visibility="gone"/> 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 <androidx.constraintlayout.widget.Barrier
android:id="@+id/barrier" android:id="@+id/barrier"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
app:barrierDirection="bottom" app:barrierDirection="bottom"
app:constraint_referenced_ids="tv_word,iv_voice"/>
app:constraint_referenced_ids="inc_word,iv_voice"/>


<!--单词测试时间--> <!--单词测试时间-->
<ProgressBar <ProgressBar

+ 73
- 0
app/src/main/res/layout/inc_learn_spell.xml View File

<?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>

+ 72
- 60
app/src/main/res/layout/inc_learn_title.xml View File

<?xml version="1.0" encoding="utf-8"?> <?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:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" 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"> 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_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>

+ 100
- 0
app/src/main/res/layout/inc_learn_word.xml View File

<?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>

+ 22
- 0
app/src/main/res/layout/inc_word.xml View File

<?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" />

+ 110
- 0
app/src/main/res/layout/inc_word_detail.xml View File

<?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>

+ 25
- 0
app/src/main/res/layout/item_historical_route.xml View File

<?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>

+ 4
- 0
app/src/main/res/values/colors.xml View File

<color name="red_3">#FF0000</color> <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="num0">#E50213</color>
<color name="num1">#E50251</color> <color name="num1">#E50251</color>

+ 11
- 6
app/src/main/res/values/strings.xml View File

<string name="continue_learn">继续学习</string> <string name="continue_learn">继续学习</string>
<string name="test_again">再测一次</string> <string name="test_again">再测一次</string>
<string name="test_type_after_total">学后总测试</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_first_fragment">Hello first fragment</string>
<string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string> <string name="hello_second_fragment">Hello second fragment. Arg: %1$s</string>
<string name="lesson_relearn_content">但不会清空测试与备忘本数据</string> <string name="lesson_relearn_content">但不会清空测试与备忘本数据</string>
<string name="sure">确定</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> </resources>

+ 11
- 0
app/src/main/res/values/styles.xml View File

<item name="android:layout_marginTop">66dp</item> <item name="android:layout_marginTop">66dp</item>
<item name="android:backgroundTint">@color/theme_color</item> <item name="android:backgroundTint">@color/theme_color</item>
</style> </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 --> <!--dialog style -->
<style name="dialog_style" parent="@android:style/Theme.Dialog"> <style name="dialog_style" parent="@android:style/Theme.Dialog">

+ 12
- 0
app/svg/drawable/ic_play.xml View File

<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>

+ 12
- 0
app/svg/drawable/ic_play_pause.xml View File

<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>

+ 74
- 0
app/svg/drawable/ic_play_stop.xml View File

<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>

+ 1
- 1
build.gradle View File

min_sdk_version : 21, min_sdk_version : 21,
target_sdk_version : 31, target_sdk_version : 31,
version_code : 100, version_code : 100,
version_name : "100",
version_name : "1.0.0",
applicationId : "com.xkl.cdl" applicationId : "com.xkl.cdl"
] ]
versions = [ versions = [

+ 8
- 9
lib/common/src/main/java/com/suliang/common/base/adapter/BaseRVAdapter.kt View File

notifyDataSetChanged() notifyDataSetChanged()
} }










/** /**
* 添加单条数据 * 添加单条数据
* @param data T? * @param data T?
* @param position Int? * @param position Int?
*/ */
fun addData(data: T?, position: Int?) {
open fun addData(data: T?, position: Int?) {
data?.let { data?.let {
val size = mData.size val size = mData.size
val startPosition = position?.let { it -> val startPosition = position?.let { it ->
} }
} }


fun removeData(position:Int){
if(mData.size >= position){
mData.removeAt(position)
notifyItemRangeChanged(position,mData.size-position)
}
}







+ 25
- 0
lib/common/src/main/java/com/suliang/common/util/ColorUtil.kt View File

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
}
}
}

+ 78
- 4
lib/common/src/main/java/com/suliang/common/util/StringUtil.kt View File

package com.suliang.common.util 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()
}
}
} }

+ 9
- 3
lib/common/src/main/java/com/suliang/common/util/os/ScreenUtil.kt View File

import android.content.res.Resources import android.content.res.Resources
import android.os.Build import android.os.Build
import android.util.DisplayMetrics import android.util.DisplayMetrics
import android.util.TypedValue
import android.view.ViewConfiguration import android.view.ViewConfiguration
import android.view.WindowManager import android.view.WindowManager
import com.suliang.common.util.AppGlobals import com.suliang.common.util.AppGlobals
/** /**
* dp2px * 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()
} }


/** /**

+ 169
- 0
lib/common/src/main/java/com/suliang/common/widget/TagLinearLayout.java View File

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();
}
}
}

+ 1
- 1
lib/common/src/main/java/com/suliang/common/widget/TitleBar.kt View File

context.obtainStyledAttributes(attrs, R.styleable.TitleBar).run { context.obtainStyledAttributes(attrs, R.styleable.TitleBar).run {
val barBackground = getColor(R.styleable.TitleBar_barBackground, 0) val barBackground = getColor(R.styleable.TitleBar_barBackground, 0)
val titleTextValue = getString(R.styleable.TitleBar_titleTextValue) 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 titleTextColor = getColor(R.styleable.TitleBar_titleTextColor, Color.parseColor("#323232"))
val rightTextValue = getString(R.styleable.TitleBar_rightTextValue) val rightTextValue = getString(R.styleable.TitleBar_rightTextValue)
val rightTextColor = getColor(R.styleable.TitleBar_rightTextColor, 0) val rightTextColor = getColor(R.styleable.TitleBar_rightTextColor, 0)

+ 5
- 1
lib/common/src/main/res/values/attrs.xml View File

<attr name="backTextColor" format="color"/> <!--左侧大小--> <attr name="backTextColor" format="color"/> <!--左侧大小-->
<attr name="backSrc" format="reference|integer"/> <!--左侧图片--> <attr name="backSrc" format="reference|integer"/> <!--左侧图片-->
<attr name="drawPadding" format="dimension"/> <!--图片drawPadding--> <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> </declare-styleable>
</resources> </resources>

Loading…
Cancel
Save