├── .idea ├── .name ├── copyright │ └── profiles_settings.xml ├── encodings.xml ├── vcs.xml ├── modules.xml ├── runConfigurations.xml ├── compiler.xml ├── gradle.xml └── misc.xml ├── app ├── .gitignore ├── libs │ └── Msc.jar ├── src │ ├── main │ │ ├── res │ │ │ ├── raw │ │ │ │ └── words.db │ │ │ ├── mipmap-xhdpi │ │ │ │ ├── icon.png │ │ │ │ ├── bottom_bg.png │ │ │ │ ├── gre_normal.png │ │ │ │ ├── launch_bg.png │ │ │ │ ├── main_logo.png │ │ │ │ ├── word_line.png │ │ │ │ ├── word_trans.png │ │ │ │ ├── cet4_normal.png │ │ │ │ ├── cet4_pressed.png │ │ │ │ ├── cet6_normal.png │ │ │ │ ├── cet6_pressed.png │ │ │ │ ├── gre_pressed.png │ │ │ │ ├── ietsl_normal.png │ │ │ │ ├── nmet_normal.png │ │ │ │ ├── nmet_pressed.png │ │ │ │ ├── word_example.png │ │ │ │ ├── btn_next_normal.png │ │ │ │ ├── btn_play_normal.png │ │ │ │ ├── btn_set_normal.png │ │ │ │ ├── btn_set_pressed.png │ │ │ │ ├── ic_menu_search.png │ │ │ │ ├── icon_speaker_no.png │ │ │ │ ├── icon_speaker_on.png │ │ │ │ ├── ietsl_pressed.png │ │ │ │ ├── unit_red_normal.png │ │ │ │ ├── btn_next_pressed.png │ │ │ │ ├── btn_pause_normal.png │ │ │ │ ├── btn_pause_pressed.png │ │ │ │ ├── btn_play_pressed.png │ │ │ │ ├── icon_speaker_off.png │ │ │ │ ├── unit_blue_normal.png │ │ │ │ ├── unit_blue_pressed.png │ │ │ │ ├── unit_red_pressed.png │ │ │ │ ├── wordlist_item_img.png │ │ │ │ ├── btn_previous_normal.png │ │ │ │ ├── btn_previous_pressed.png │ │ │ │ ├── unit_yellow_normal.png │ │ │ │ ├── unit_yellow_pressed.png │ │ │ │ ├── wordlist_item_normal.jpg │ │ │ │ ├── unitlist_item_img_blue.jpg │ │ │ │ ├── unitlist_item_img_red.jpg │ │ │ │ ├── wordlist_item_pressed.jpg │ │ │ │ └── unitlist_item_img_yellow.jpg │ │ │ ├── values │ │ │ │ ├── dimens.xml │ │ │ │ ├── colors.xml │ │ │ │ ├── styles.xml │ │ │ │ └── strings.xml │ │ │ ├── drawable │ │ │ │ ├── gre_selector.xml │ │ │ │ ├── text_bottom_state.xml │ │ │ │ ├── cet4_selector.xml │ │ │ │ ├── cet6_selector.xml │ │ │ │ ├── nmet_selector.xml │ │ │ │ ├── ietsl_selector.xml │ │ │ │ ├── unit_red_bg.xml │ │ │ │ ├── btn_next_selector.xml │ │ │ │ ├── btn_play_selector.xml │ │ │ │ ├── btn_setting_selector.xml │ │ │ │ ├── unit_blue_bg.xml │ │ │ │ ├── btn_pause_selector.xml │ │ │ │ ├── unit_yellow_bg.xml │ │ │ │ ├── word_item_bg.xml │ │ │ │ └── btn_previous_selector.xml │ │ │ ├── values-w820dp │ │ │ │ └── dimens.xml │ │ │ ├── layout │ │ │ │ ├── activity_list.xml │ │ │ │ ├── activity_splash.xml │ │ │ │ ├── fragment_list.xml │ │ │ │ ├── item_word.xml │ │ │ │ ├── item_category.xml │ │ │ │ ├── activity_detail.xml │ │ │ │ ├── activity_main.xml │ │ │ │ └── fragment_detail.xml │ │ │ └── menu │ │ │ │ ├── menu_search.xml │ │ │ │ └── menu_setting.xml │ │ ├── jniLibs │ │ │ ├── armeabi │ │ │ │ └── libmsc.so │ │ │ ├── arm64-v8a │ │ │ │ └── libmsc.so │ │ │ └── armeabi-v7a │ │ │ │ └── libmsc.so │ │ ├── java │ │ │ └── com │ │ │ │ └── silence │ │ │ │ ├── utils │ │ │ │ ├── DateUtils.java │ │ │ │ ├── Const.java │ │ │ │ ├── DBOpenHelper.java │ │ │ │ ├── FileUtils.java │ │ │ │ └── WavWriter.java │ │ │ │ ├── adapter │ │ │ │ ├── WordPagerAdapter.java │ │ │ │ ├── WordAdapter.java │ │ │ │ ├── UnitAdapter.java │ │ │ │ └── CommonAdapter.java │ │ │ │ ├── pojo │ │ │ │ ├── Unit.java │ │ │ │ └── Word.java │ │ │ │ ├── activity │ │ │ │ ├── WordListActivity.java │ │ │ │ ├── MainActivity.java │ │ │ │ ├── SplashActivity.java │ │ │ │ ├── UnitListActivity.java │ │ │ │ └── DetailActivity.java │ │ │ │ ├── fragment │ │ │ │ ├── SearchFgt.java │ │ │ │ ├── DetailFgt.java │ │ │ │ ├── WordListFgt.java │ │ │ │ └── UnitListFgt.java │ │ │ │ └── dao │ │ │ │ ├── UnitDao.java │ │ │ │ └── WordDao.java │ │ └── AndroidManifest.xml │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── silence │ │ │ └── word │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── silence │ │ └── word │ │ └── ApplicationTest.java ├── proguard-rules.pro ├── build.gradle └── proguard-android.txt ├── quickscroll ├── .gitignore ├── src │ ├── main │ │ ├── res │ │ │ └── values │ │ │ │ └── strings.xml │ │ ├── AndroidManifest.xml │ │ └── java │ │ │ └── com │ │ │ └── andraskindler │ │ │ └── quickscroll │ │ │ ├── Scrollable.java │ │ │ ├── Pin.java │ │ │ ├── ViewHelper.java │ │ │ ├── animation │ │ │ └── AnimatorProxy.java │ │ │ └── QuickScroll.java │ ├── test │ │ └── java │ │ │ └── com │ │ │ └── silence │ │ │ └── quickscroll │ │ │ └── ExampleUnitTest.java │ └── androidTest │ │ └── java │ │ └── com │ │ └── silence │ │ └── quickscroll │ │ └── ApplicationTest.java ├── build.gradle └── proguard-rules.pro ├── settings.gradle ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── .gitignore ├── screenshot ├── Screenshot_2016-03-14-21-22-34_com.silence.word.png ├── Screenshot_2016-03-19-17-50-19_com.silence.word.png ├── Screenshot_2016-03-19-17-50-26_com.silence.word.png ├── Screenshot_2016-03-19-17-50-34_com.silence.word.png └── Screenshot_2016-03-19-17-51-17_com.silence.word.png ├── README.md ├── gradle.properties ├── gradlew.bat └── gradlew /.idea/.name: -------------------------------------------------------------------------------- 1 | Word -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /quickscroll/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app', ':quickscroll' 2 | -------------------------------------------------------------------------------- /app/libs/Msc.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/libs/Msc.jar -------------------------------------------------------------------------------- /app/src/main/res/raw/words.db: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/raw/words.db -------------------------------------------------------------------------------- /.idea/copyright/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /quickscroll/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | QuickScroll 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi/libmsc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/jniLibs/armeabi/libmsc.so -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/icon.png -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | -------------------------------------------------------------------------------- /app/src/main/jniLibs/arm64-v8a/libmsc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/jniLibs/arm64-v8a/libmsc.so -------------------------------------------------------------------------------- /app/src/main/jniLibs/armeabi-v7a/libmsc.so: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/jniLibs/armeabi-v7a/libmsc.so -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/bottom_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/bottom_bg.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/gre_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/gre_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/launch_bg.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/launch_bg.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/main_logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/main_logo.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/word_line.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/word_line.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/word_trans.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/word_trans.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/cet4_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/cet4_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/cet4_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/cet4_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/cet6_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/cet6_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/cet6_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/cet6_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/gre_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/gre_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ietsl_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/ietsl_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/nmet_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/nmet_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/nmet_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/nmet_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/word_example.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/word_example.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_next_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_next_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_play_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_play_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_set_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_set_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_set_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_set_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_menu_search.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/ic_menu_search.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_speaker_no.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/icon_speaker_no.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_speaker_on.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/icon_speaker_on.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ietsl_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/ietsl_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_red_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_red_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_next_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_next_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_pause_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_pause_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_pause_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_pause_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_play_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_play_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/icon_speaker_off.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/icon_speaker_off.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_blue_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_blue_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_blue_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_blue_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_red_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_red_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/wordlist_item_img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/wordlist_item_img.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_previous_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_previous_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/btn_previous_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/btn_previous_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_yellow_normal.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_yellow_normal.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unit_yellow_pressed.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unit_yellow_pressed.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/wordlist_item_normal.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/wordlist_item_normal.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unitlist_item_img_blue.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unitlist_item_img_blue.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unitlist_item_img_red.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unitlist_item_img_red.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/wordlist_item_pressed.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/wordlist_item_pressed.jpg -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/unitlist_item_img_yellow.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/app/src/main/res/mipmap-xhdpi/unitlist_item_img_yellow.jpg -------------------------------------------------------------------------------- /screenshot/Screenshot_2016-03-14-21-22-34_com.silence.word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/screenshot/Screenshot_2016-03-14-21-22-34_com.silence.word.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2016-03-19-17-50-19_com.silence.word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/screenshot/Screenshot_2016-03-19-17-50-19_com.silence.word.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2016-03-19-17-50-26_com.silence.word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/screenshot/Screenshot_2016-03-19-17-50-26_com.silence.word.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2016-03-19-17-50-34_com.silence.word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/screenshot/Screenshot_2016-03-19-17-50-34_com.silence.word.png -------------------------------------------------------------------------------- /screenshot/Screenshot_2016-03-19-17-51-17_com.silence.word.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/isuperqiang/Android-Word/HEAD/screenshot/Screenshot_2016-03-19-17-51-17_com.silence.word.png -------------------------------------------------------------------------------- /.idea/encodings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5dp 4 | 5dp 5 | 6 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Wed Oct 21 11:34:03 PDT 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.8-all.zip 7 | -------------------------------------------------------------------------------- /quickscroll/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 3 | 4 | 9 | 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/gre_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/text_bottom_state.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cet4_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/cet6_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/nmet_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ietsl_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/unit_red_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_next_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_play_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_setting_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/unit_blue_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_pause_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/unit_yellow_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/word_item_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/btn_previous_selector.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /app/src/test/java/com/silence/word/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.silence.word; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | -------------------------------------------------------------------------------- /quickscroll/src/test/java/com/silence/quickscroll/ExampleUnitTest.java: -------------------------------------------------------------------------------- 1 | package com.silence.quickscroll; 2 | 3 | import org.junit.Test; 4 | 5 | import static org.junit.Assert.*; 6 | 7 | /** 8 | * To work on unit tests, switch the Test Artifact in the Build Variants view. 9 | */ 10 | public class ExampleUnitTest { 11 | @Test 12 | public void addition_isCorrect() throws Exception { 13 | assertEquals(4, 2 + 2); 14 | } 15 | } -------------------------------------------------------------------------------- /app/src/androidTest/java/com/silence/word/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.silence.word; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /quickscroll/src/androidTest/java/com/silence/quickscroll/ApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.silence.quickscroll; 2 | 3 | import android.app.Application; 4 | import android.test.ApplicationTestCase; 5 | 6 | /** 7 | * Testing Fundamentals 8 | */ 9 | public class ApplicationTest extends ApplicationTestCase { 10 | public ApplicationTest() { 11 | super(Application.class); 12 | } 13 | } -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_search.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 11 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/utils/DateUtils.java: -------------------------------------------------------------------------------- 1 | package com.silence.utils; 2 | 3 | /** 4 | * Created by Silence on 2016/2/9 0009. 5 | */ 6 | public class DateUtils { 7 | 8 | private DateUtils() { 9 | } 10 | 11 | public static String formatTime(long duration) { 12 | long hour = duration / (60 * 60 * 1000); 13 | long min = (duration % (60 * 60 * 1000)) / (60 * 1000); 14 | long sec = (duration % (60 * 1000)) / 1000; 15 | return (hour != 0 ? hour + "小时" : "") + (min != 0 ? min + "分钟" : "") + sec + "秒"; 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 记单词 App 2 | ====== 3 | 本软件包含高考、四六级、托福雅思单词,是帮你备考各类考试的好助手。 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #BF000000 7 | #DF000000 8 | #EF000000 9 | #AF000000 10 | #BF000000 11 | #ffff4444 12 | #ffcc0000 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_splash.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_setting.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 12 | 18 | -------------------------------------------------------------------------------- /quickscroll/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.library' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.2" 6 | 7 | defaultConfig { 8 | minSdkVersion 15 9 | targetSdkVersion 23 10 | versionCode 1 11 | versionName "1.0" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | testCompile 'junit:junit:4.12' 24 | compile 'com.android.support:appcompat-v7:23.2.1' 25 | } 26 | -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Andriod SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /quickscroll/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in E:\Andriod SDK/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 13 | 14 | 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/utils/Const.java: -------------------------------------------------------------------------------- 1 | package com.silence.utils; 2 | 3 | /** 4 | * Created by Silence on 2016/2/11 0011. 5 | */ 6 | public interface Const { 7 | String META_KEY = "com.silence.table.meta"; 8 | String UNIT_KEY = "com.silence.unit.key"; 9 | String WORD_KEY = "com.silence.word.key"; 10 | String WORDS_NMET = "TABLE_NMET"; 11 | String WORDS_CET4 = "TABLE_CET4"; 12 | String WORDS_CET6 = "TABLE_CET6"; 13 | String WORDS_IETSL = "TABLE_IETSL"; 14 | String WORDS_GRE = "TABLE_GRE"; 15 | String SP_KEY = "exist"; 16 | String DB_NAME = "words.db"; 17 | String DB_DIR = "databases"; 18 | long DELAY_TIME = 1000; 19 | String PLAY_SPEED = "play_speed"; 20 | String AUTO_SPEAK = "auto_speak"; 21 | String[] META_KEYS = {WORDS_NMET, WORDS_CET4, WORDS_CET6, WORDS_IETSL, WORDS_GRE}; 22 | } 23 | -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 23 5 | buildToolsVersion "23.0.3" 6 | 7 | defaultConfig { 8 | applicationId "com.silence.word" 9 | minSdkVersion 15 10 | targetSdkVersion 23 11 | versionCode 1 12 | versionName "1.0" 13 | } 14 | buildTypes { 15 | release { 16 | minifyEnabled true 17 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 18 | } 19 | } 20 | } 21 | 22 | dependencies { 23 | compile fileTree(include: ['*.jar'], dir: 'libs') 24 | testCompile 'junit:junit:4.12' 25 | compile 'com.android.support:appcompat-v7:23.1.1' 26 | compile 'com.android.support:support-v4:23.1.1' 27 | compile project(':quickscroll') 28 | compile files('libs/Msc.jar') 29 | } 30 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | # Default value: -Xmx10248m -XX:MaxPermSize=256m 13 | # org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8 14 | 15 | # When configured, Gradle will run in incubating parallel mode. 16 | # This option should only be used with decoupled projects. More details, visit 17 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 18 | # org.gradle.parallel=true -------------------------------------------------------------------------------- /app/src/main/java/com/silence/utils/DBOpenHelper.java: -------------------------------------------------------------------------------- 1 | package com.silence.utils; 2 | 3 | import android.content.Context; 4 | import android.database.sqlite.SQLiteDatabase; 5 | 6 | import java.io.File; 7 | 8 | /** 9 | * Created by Silence on 2016/1/30 0030. 10 | */ 11 | public class DBOpenHelper { 12 | private static DBOpenHelper sDBOpenHelper; 13 | private Context mContext; 14 | 15 | private DBOpenHelper(Context context) { 16 | mContext = context; 17 | } 18 | 19 | public static DBOpenHelper getInstance(Context context) { 20 | if (sDBOpenHelper == null) { 21 | sDBOpenHelper = new DBOpenHelper(context); 22 | } 23 | return sDBOpenHelper; 24 | } 25 | 26 | public SQLiteDatabase getDatabase() { 27 | String path = mContext.getDir(Const.DB_DIR, Context.MODE_PRIVATE) + File.separator + Const.DB_NAME; 28 | return SQLiteDatabase.openDatabase(path, null, SQLiteDatabase.OPEN_READWRITE); 29 | } 30 | } -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_word.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 17 | 18 | 29 | -------------------------------------------------------------------------------- /quickscroll/src/main/java/com/andraskindler/quickscroll/Scrollable.java: -------------------------------------------------------------------------------- 1 | package com.andraskindler.quickscroll; 2 | 3 | /** 4 | * Interface required for FastTrack. 5 | * 6 | * @author andraskindler 7 | */ 8 | public interface Scrollable { 9 | 10 | /** 11 | * This function returns the corresponding String to display at any given position 12 | * 13 | * 14 | * @param childposition equals childposition if used with ExpandableListView, position otherwise. 15 | * @param groupposition equals groupposition if used with ExpandableListView, zero otherwise. 16 | */ 17 | String getIndicatorForPosition(final int childposition, final int groupposition); 18 | 19 | /** 20 | * This second function is responsible for is for implementing scroll behaviour. This can be used to perform special tasks, e.g. if you want to snap to the first item starting with a letter in an alphabetically ordered list or jump between groups in an ExpandableListView. If you want the normal approach, simply return childposition. 21 | * 22 | * 23 | * @param childposition equals childposition if used with ExpandableListView, position otherwise. 24 | * @param groupposition equals groupposition if used with ExpandableListView, zero otherwise. 25 | */ 26 | int getScrollPosition(final int childposition, final int groupposition); 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/adapter/WordPagerAdapter.java: -------------------------------------------------------------------------------- 1 | package com.silence.adapter; 2 | 3 | import android.support.v4.app.Fragment; 4 | import android.support.v4.app.FragmentManager; 5 | import android.support.v4.app.FragmentStatePagerAdapter; 6 | import android.util.SparseArray; 7 | import android.view.ViewGroup; 8 | 9 | import com.silence.fragment.DetailFgt; 10 | import com.silence.pojo.Word; 11 | 12 | import java.util.List; 13 | 14 | /** 15 | * Created by Silence on 2016/2/9 0009. 16 | */ 17 | public class WordPagerAdapter extends FragmentStatePagerAdapter { 18 | 19 | private List mWordList; 20 | private SparseArray mFragments; 21 | 22 | public WordPagerAdapter(FragmentManager fm, List wordList) { 23 | super(fm); 24 | mWordList = wordList; 25 | mFragments=new SparseArray<>(mWordList.size()); 26 | } 27 | 28 | @Override 29 | public Fragment getItem(int position) { 30 | DetailFgt detailFgt = DetailFgt.newInstance(mWordList.get(position)); 31 | mFragments.put(position, detailFgt); 32 | return detailFgt; 33 | } 34 | 35 | @Override 36 | public void destroyItem(ViewGroup container, int position, Object object) { 37 | super.destroyItem(container, position, object); 38 | mFragments.remove(position); 39 | } 40 | 41 | @Override 42 | public int getCount() { 43 | return mWordList.size(); 44 | } 45 | 46 | public Fragment getFragment(int position) { 47 | return mFragments.get(position); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_category.xml: -------------------------------------------------------------------------------- 1 | 2 | 12 | 13 | 22 | 23 | 33 | 34 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 24 | 25 | 31 | 32 | 38 | 39 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /quickscroll/src/main/java/com/andraskindler/quickscroll/Pin.java: -------------------------------------------------------------------------------- 1 | package com.andraskindler.quickscroll; 2 | 3 | import android.content.Context; 4 | import android.graphics.Canvas; 5 | import android.graphics.Color; 6 | import android.graphics.Paint; 7 | import android.graphics.Path; 8 | import android.util.AttributeSet; 9 | import android.view.View; 10 | 11 | public class Pin extends View { 12 | 13 | private static final int mPinColor = Color.argb(224, 66, 66, 66); 14 | private Paint mPaint; 15 | private Path mPath; 16 | 17 | public Pin(Context context) { 18 | super(context); 19 | init(); 20 | } 21 | 22 | public Pin(Context context, AttributeSet attrs) { 23 | super(context, attrs); 24 | init(); 25 | } 26 | 27 | public Pin(Context context, AttributeSet attrs, int defStyle) { 28 | super(context, attrs, defStyle); 29 | init(); 30 | } 31 | 32 | public void setColor(int color) { 33 | mPaint.setColor(color); 34 | } 35 | 36 | private void init() { 37 | mPath = new Path(); 38 | mPaint = new Paint(); 39 | mPaint.setAntiAlias(true); 40 | mPaint.setStyle(Paint.Style.FILL); 41 | setColor(mPinColor); 42 | } 43 | 44 | @Override 45 | protected void onLayout(boolean changed, int left, int top, int right, int bottom) { 46 | if (changed) { 47 | mPath.reset(); 48 | mPath.moveTo(0, getHeight()); 49 | mPath.lineTo(getWidth(), getHeight() / 2); 50 | mPath.lineTo(0, 0); 51 | mPath.close(); 52 | } 53 | super.onLayout(changed, left, top, right, bottom); 54 | } 55 | 56 | @Override 57 | protected void onDraw(Canvas canvas) { 58 | canvas.drawPath(mPath, mPaint); 59 | super.onDraw(canvas); 60 | } 61 | 62 | } 63 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/pojo/Unit.java: -------------------------------------------------------------------------------- 1 | package com.silence.pojo; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * Created by Silence on 2016/2/8 0008. 8 | */ 9 | public class Unit implements Parcelable { 10 | private int mKey; 11 | private long mTime; 12 | private String mMetaKey; 13 | 14 | public Unit() { 15 | } 16 | 17 | public Unit(int key, long time, String metaKey) { 18 | mKey = key; 19 | mTime = time; 20 | mMetaKey = metaKey; 21 | } 22 | 23 | public int getKey() { 24 | return mKey; 25 | } 26 | 27 | public void setKey(int key) { 28 | mKey = key; 29 | } 30 | 31 | public long getTime() { 32 | return mTime; 33 | } 34 | 35 | public void setTime(long time) { 36 | mTime = time; 37 | } 38 | 39 | public String getMetaKey() { 40 | return mMetaKey; 41 | } 42 | 43 | public void setMetaKey(String metaKey) { 44 | mMetaKey = metaKey; 45 | } 46 | 47 | @Override 48 | public int describeContents() { 49 | return 0; 50 | } 51 | 52 | @Override 53 | public void writeToParcel(Parcel dest, int flags) { 54 | dest.writeInt(this.mKey); 55 | dest.writeLong(this.mTime); 56 | dest.writeString(this.mMetaKey); 57 | } 58 | 59 | protected Unit(Parcel in) { 60 | this.mKey = in.readInt(); 61 | this.mTime = in.readLong(); 62 | this.mMetaKey = in.readString(); 63 | } 64 | 65 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 66 | public Unit createFromParcel(Parcel source) { 67 | return new Unit(source); 68 | } 69 | 70 | public Unit[] newArray(int size) { 71 | return new Unit[size]; 72 | } 73 | }; 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/utils/FileUtils.java: -------------------------------------------------------------------------------- 1 | package com.silence.utils; 2 | 3 | import android.content.Context; 4 | 5 | import com.silence.word.R; 6 | 7 | import java.io.File; 8 | import java.io.FileOutputStream; 9 | import java.io.IOException; 10 | import java.io.InputStream; 11 | 12 | /** 13 | * Created by Silence on 2016/2/11 0011. 14 | */ 15 | public class FileUtils { 16 | private FileUtils() { 17 | } 18 | 19 | public static void writeData(Context context) { 20 | String dbPath = context.getDir(Const.DB_DIR, Context.MODE_PRIVATE) + File.separator + Const.DB_NAME; 21 | File dbFile = new File(dbPath); 22 | if (!dbFile.exists()) { 23 | InputStream inputStream = context.getResources().openRawResource(R.raw.words); 24 | FileOutputStream fileOutputStream = null; 25 | try { 26 | fileOutputStream = new FileOutputStream(dbFile); 27 | int len; 28 | byte[] bytes = new byte[1024]; 29 | while ((len = inputStream.read(bytes)) != -1) { 30 | fileOutputStream.write(bytes, 0, len); 31 | } 32 | } catch (IOException e) { 33 | e.printStackTrace(); 34 | } finally { 35 | if (fileOutputStream != null) { 36 | try { 37 | fileOutputStream.close(); 38 | } catch (IOException e) { 39 | e.printStackTrace(); 40 | } finally { 41 | if (inputStream != null) { 42 | try { 43 | inputStream.close(); 44 | } catch (IOException e) { 45 | e.printStackTrace(); 46 | } 47 | } 48 | } 49 | } 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 记词 3 | launch background 4 | main logo 5 | nmet button 6 | cet4 button 7 | cet6 button 8 | ietsl button 9 | gre button 10 | category image 11 | 没有查到数据 12 | 全国高考英语词汇 13 | 大学英语四级词汇 14 | 大学英语六级词汇 15 | 雅思词汇 16 | 美国研究生入学考试词汇 17 | Unit 18 | word list image 19 | image_trans 20 | previous button 21 | 后退 22 | 播放 23 | 停止 24 | 前进 25 | 自动发音 26 | 播放速度 27 | 选择速度 28 | search 29 | 已经第一页 30 | 到达最后一页 31 | 请输入要查询的单词 32 | 累计阅读: 33 | 34 | 极快 35 | 稍快 36 | 普通 37 | 稍慢 38 | 极慢 39 | 40 | 41 | 42 | Hello blank fragment 43 | 再按一次退出程序 44 | 当前播放速度过快, 无法自动发音, 请调慢速度 45 | 请检查是否连接网络 46 | 47 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/activity/WordListActivity.java: -------------------------------------------------------------------------------- 1 | package com.silence.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.ActionBar; 6 | import android.support.v7.app.AppCompatActivity; 7 | import android.view.MenuItem; 8 | 9 | import com.silence.fragment.WordListFgt; 10 | import com.silence.pojo.Unit; 11 | import com.silence.utils.Const; 12 | import com.silence.word.R; 13 | 14 | public class WordListActivity extends AppCompatActivity implements WordListFgt.onWordClickListener { 15 | 16 | @Override 17 | protected void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_list); 20 | ActionBar actionBar = getSupportActionBar(); 21 | if (actionBar != null) { 22 | actionBar.setDisplayHomeAsUpEnabled(true); 23 | } 24 | Unit unit = getIntent().getParcelableExtra(Const.UNIT_KEY); 25 | if (unit != null) { 26 | String cat = unit.getMetaKey(); 27 | setTitle(cat.substring(cat.indexOf("_") + 1, cat.length()) + " - Unit - " + unit.getKey()); 28 | if (savedInstanceState == null) { 29 | WordListFgt wordListFgt = WordListFgt.newInstance(unit.getMetaKey(), unit.getKey()); 30 | getSupportFragmentManager().beginTransaction().add(R.id.unit_content, wordListFgt).commit(); 31 | } 32 | } 33 | } 34 | 35 | @Override 36 | public boolean onOptionsItemSelected(MenuItem item) { 37 | if (item.getItemId() == android.R.id.home) { 38 | finish(); 39 | return true; 40 | } 41 | return super.onOptionsItemSelected(item); 42 | } 43 | 44 | @Override 45 | public void getWordList(String metaKey, int unitKey, int wordKey) { 46 | Intent intent = new Intent(this, DetailActivity.class); 47 | intent.putExtra(Const.META_KEY, metaKey); 48 | intent.putExtra(Const.UNIT_KEY, unitKey); 49 | intent.putExtra(Const.WORD_KEY, wordKey); 50 | startActivity(intent); 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 21 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 35 | 36 | 40 | 41 | 45 | 46 | 50 | 51 | 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/adapter/WordAdapter.java: -------------------------------------------------------------------------------- 1 | package com.silence.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.TextView; 9 | 10 | import com.andraskindler.quickscroll.Scrollable; 11 | import com.silence.pojo.Word; 12 | import com.silence.word.R; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by Silence on 2016/3/18 0018. 18 | */ 19 | public class WordAdapter extends BaseAdapter implements Scrollable { 20 | private Context mContext; 21 | private List mWordList; 22 | 23 | public WordAdapter(Context context, List wordList) { 24 | mContext = context; 25 | mWordList = wordList; 26 | } 27 | 28 | @Override 29 | public int getCount() { 30 | return mWordList != null ? mWordList.size() : 0; 31 | } 32 | 33 | @Override 34 | public Object getItem(int position) { 35 | return mWordList != null ? mWordList.get(position) : null; 36 | } 37 | 38 | @Override 39 | public long getItemId(int position) { 40 | return position; 41 | } 42 | 43 | @Override 44 | public View getView(int position, View convertView, ViewGroup parent) { 45 | ViewHolder viewHolder; 46 | if (convertView == null) { 47 | convertView = LayoutInflater.from(mContext).inflate(R.layout.item_word, parent, false); 48 | viewHolder = new ViewHolder(); 49 | viewHolder.tvWord = (TextView) convertView.findViewById(R.id.tv_item_word); 50 | convertView.setTag(viewHolder); 51 | } else { 52 | viewHolder = (ViewHolder) convertView.getTag(); 53 | } 54 | viewHolder.tvWord.setText(mWordList.get(position).getKey()); 55 | return convertView; 56 | } 57 | 58 | @Override 59 | public String getIndicatorForPosition(int childposition, int groupposition) { 60 | return String.valueOf(mWordList.get(childposition).getKey().charAt(0)); 61 | } 62 | 63 | @Override 64 | public int getScrollPosition(int childposition, int groupposition) { 65 | return childposition; 66 | } 67 | 68 | static class ViewHolder { 69 | TextView tvWord; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/fragment/SearchFgt.java: -------------------------------------------------------------------------------- 1 | package com.silence.fragment; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.support.v4.app.ListFragment; 6 | import android.view.View; 7 | import android.widget.ListView; 8 | 9 | import com.silence.adapter.CommonAdapter; 10 | import com.silence.pojo.Word; 11 | import com.silence.utils.Const; 12 | import com.silence.word.R; 13 | 14 | import java.util.List; 15 | 16 | /** 17 | * Created by Silence on 2016/2/11 0011. 18 | */ 19 | public class SearchFgt extends ListFragment { 20 | 21 | private CommonAdapter mCommonAdapter; 22 | private onSearchClickListener mOnSearchClickListener; 23 | 24 | public static SearchFgt newInstance(String metaKey) { 25 | Bundle bundle = new Bundle(); 26 | bundle.putString(Const.META_KEY, metaKey); 27 | SearchFgt searchFgt = new SearchFgt(); 28 | searchFgt.setArguments(bundle); 29 | return searchFgt; 30 | } 31 | 32 | @Override 33 | public void onAttach(Context context) { 34 | super.onAttach(context); 35 | if (context instanceof onSearchClickListener) { 36 | mOnSearchClickListener = (onSearchClickListener) context; 37 | } 38 | } 39 | 40 | @Override 41 | public void onCreate(Bundle savedInstanceState) { 42 | super.onCreate(savedInstanceState); 43 | mCommonAdapter = new CommonAdapter(null, R.layout.item_word) { 44 | @Override 45 | public void bindView(ViewHolder holder, Word obj) { 46 | holder.setText(R.id.tv_item_word, obj.getKey()); 47 | } 48 | }; 49 | setListAdapter(mCommonAdapter); 50 | } 51 | 52 | @Override 53 | public void onDetach() { 54 | super.onDetach(); 55 | mOnSearchClickListener = null; 56 | } 57 | 58 | public void refresh(List wordList) { 59 | mCommonAdapter.setData(wordList); 60 | } 61 | 62 | @Override 63 | public void onListItemClick(ListView l, View v, int position, long id) { 64 | if (mOnSearchClickListener != null) { 65 | mOnSearchClickListener.getWord((Word) l.getItemAtPosition(position)); 66 | } 67 | } 68 | 69 | public interface onSearchClickListener { 70 | void getWord(Word word); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/dao/UnitDao.java: -------------------------------------------------------------------------------- 1 | package com.silence.dao; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | 7 | import com.silence.pojo.Unit; 8 | import com.silence.utils.DBOpenHelper; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by Silence on 2016/2/8 0008. 15 | */ 16 | public class UnitDao { 17 | private DBOpenHelper mDBOpenHelper; 18 | 19 | public UnitDao(Context context) { 20 | mDBOpenHelper = DBOpenHelper.getInstance(context); 21 | } 22 | 23 | public List getUnits(String metaKey) { 24 | List units = null; 25 | String sql = "select Unit_Key, Unit_Time from TABLE_UNIT where Cate_Key=?"; 26 | SQLiteDatabase db = mDBOpenHelper.getDatabase(); 27 | Cursor cursor = db.rawQuery(sql, new String[]{metaKey}); 28 | if (cursor.moveToFirst()) { 29 | Unit unit; 30 | units = new ArrayList<>(cursor.getCount()); 31 | do { 32 | int key = cursor.getInt(cursor.getColumnIndex("Unit_Key")); 33 | long time = cursor.getLong(cursor.getColumnIndex("Unit_Time")); 34 | unit = new Unit(key, time, metaKey); 35 | units.add(unit); 36 | } while (cursor.moveToNext()); 37 | } 38 | cursor.close(); 39 | return units; 40 | } 41 | 42 | public void updateTime(String metaKey, int unitKey, long time) { 43 | String sqlUpdate = "update TABLE_UNIT set Unit_Time=? where Unit_Key=? and Cate_Key=?;"; 44 | SQLiteDatabase db = mDBOpenHelper.getDatabase(); 45 | db.execSQL(sqlUpdate, new Object[]{time + getTime(metaKey, unitKey), unitKey, metaKey}); 46 | } 47 | 48 | public long getTime(String metaKey, int unitKey) { 49 | String sql = "select Unit_Time from TABLE_UNIT where Unit_Key=? and Cate_Key=?;"; 50 | SQLiteDatabase db = mDBOpenHelper.getDatabase(); 51 | Cursor cursor = db.rawQuery(sql, new String[]{String.valueOf(unitKey), metaKey}); 52 | long existTime = 0; 53 | if (cursor.moveToFirst()) { 54 | existTime = cursor.getLong(cursor.getColumnIndex("Unit_Time")); 55 | } 56 | cursor.close(); 57 | return existTime; 58 | } 59 | 60 | } 61 | -------------------------------------------------------------------------------- /app/proguard-android.txt: -------------------------------------------------------------------------------- 1 | # This is a configuration file for ProGuard. 2 | # http://proguard.sourceforge.net/index.html#manual/usage.html 3 | 4 | -dontusemixedcaseclassnames 5 | -dontskipnonpubliclibraryclasses 6 | -verbose 7 | 8 | # Optimization is turned off by default. Dex does not like code run 9 | # through the ProGuard optimize and preverify steps (and performs some 10 | # of these optimizations on its own). 11 | -dontoptimize 12 | -dontpreverify 13 | # Note that if you want to enable optimization, you cannot just 14 | # include optimization flags in your own project configuration file; 15 | # instead you will need to point to the 16 | # "proguard-android-optimize.txt" file instead of this one from your 17 | # project.properties file. 18 | 19 | -keepattributes *Annotation* 20 | -keep public class com.google.vending.licensing.ILicensingService 21 | -keep public class com.android.vending.licensing.ILicensingService 22 | 23 | # For native methods, see http://proguard.sourceforge.net/manual/examples.html#native 24 | -keepclasseswithmembernames class * { 25 | native ; 26 | } 27 | -keep class com.iflytek.**{*;} 28 | -keepattributes Signature 29 | # keep setters in Views so that animations can still work. 30 | # see http://proguard.sourceforge.net/manual/examples.html#beans 31 | -keepclassmembers public class * extends android.view.View { 32 | void set*(***); 33 | *** get*(); 34 | } 35 | 36 | # We want to keep methods in Activity that could be used in the XML attribute onClick 37 | -keepclassmembers class * extends android.app.Activity { 38 | public void *(android.view.View); 39 | } 40 | 41 | # For enumeration classes, see http://proguard.sourceforge.net/manual/examples.html#enumerations 42 | -keepclassmembers enum * { 43 | public static **[] values(); 44 | public static ** valueOf(java.lang.String); 45 | } 46 | 47 | -dontwarn net.youmi.android.** 48 | -keep class net.youmi.android.** { 49 | *; 50 | } 51 | 52 | -keepclassmembers class * implements android.os.Parcelable { 53 | public static final android.os.Parcelable$Creator CREATOR; 54 | } 55 | 56 | -keepclassmembers class **.R$* { 57 | public static ; 58 | } 59 | 60 | # The support library contains references to newer platform versions. 61 | # Don't warn about those in case this app is linking against an older 62 | # platform version. We know about them, and they are safe. 63 | -dontwarn android.support.** 64 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 15 | 16 | 20 | 21 | 29 | 30 | 38 | 39 | 40 | 43 | 44 | 52 | 53 | 61 | 62 | 63 | 72 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/activity/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.silence.activity; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.KeyEvent; 7 | import android.view.View; 8 | import android.widget.Toast; 9 | 10 | import com.silence.utils.Const; 11 | import com.silence.word.R; 12 | 13 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 14 | 15 | private long exitTime = 0; 16 | 17 | @Override 18 | protected void onCreate(Bundle savedInstanceState) { 19 | super.onCreate(savedInstanceState); 20 | setContentView(R.layout.activity_main); 21 | findViewById(R.id.iv_cet4).setOnClickListener(this); 22 | findViewById(R.id.iv_cet6).setOnClickListener(this); 23 | findViewById(R.id.iv_gre).setOnClickListener(this); 24 | findViewById(R.id.iv_ietsl).setOnClickListener(this); 25 | findViewById(R.id.iv_nmet).setOnClickListener(this); 26 | } 27 | 28 | @Override 29 | public void onClick(View v) { 30 | Intent intent = new Intent(); 31 | switch (v.getId()) { 32 | case R.id.iv_nmet: 33 | intent.setClass(this, UnitListActivity.class); 34 | intent.putExtra(Const.META_KEY, Const.WORDS_NMET); 35 | break; 36 | case R.id.iv_cet4: 37 | intent.setClass(this, UnitListActivity.class); 38 | intent.putExtra(Const.META_KEY, Const.WORDS_CET4); 39 | break; 40 | case R.id.iv_cet6: 41 | intent.setClass(this, UnitListActivity.class); 42 | intent.putExtra(Const.META_KEY, Const.WORDS_CET6); 43 | break; 44 | case R.id.iv_ietsl: 45 | intent.setClass(this, UnitListActivity.class); 46 | intent.putExtra(Const.META_KEY, Const.WORDS_IETSL); 47 | break; 48 | case R.id.iv_gre: 49 | intent.setClass(this, UnitListActivity.class); 50 | intent.putExtra(Const.META_KEY, Const.WORDS_GRE); 51 | break; 52 | } 53 | startActivity(intent); 54 | } 55 | 56 | @Override 57 | public boolean onKeyDown(int keyCode, KeyEvent event) { 58 | if (keyCode == KeyEvent.KEYCODE_BACK && event.getAction() == KeyEvent.ACTION_DOWN) { 59 | if ((System.currentTimeMillis() - exitTime) > 2000) { 60 | Toast.makeText(this, R.string.exit_hint, Toast.LENGTH_SHORT).show(); 61 | exitTime = System.currentTimeMillis(); 62 | } else { 63 | finish(); 64 | } 65 | return true; 66 | } 67 | return super.onKeyDown(keyCode, event); 68 | } 69 | } -------------------------------------------------------------------------------- /app/src/main/java/com/silence/fragment/DetailFgt.java: -------------------------------------------------------------------------------- 1 | package com.silence.fragment; 2 | 3 | 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.ImageView; 11 | import android.widget.TextView; 12 | 13 | import com.silence.pojo.Word; 14 | import com.silence.utils.Const; 15 | import com.silence.word.R; 16 | 17 | /** 18 | * Created by Silence on 2016/2/9 0009. 19 | */ 20 | public class DetailFgt extends Fragment { 21 | private onSpeechListener mOnSpeechListener; 22 | private ImageView mImageView; 23 | 24 | public static DetailFgt newInstance(Word word) { 25 | Bundle bundle = new Bundle(); 26 | bundle.putParcelable(Const.WORD_KEY, word); 27 | DetailFgt detailFgt = new DetailFgt(); 28 | detailFgt.setArguments(bundle); 29 | return detailFgt; 30 | } 31 | 32 | @Override 33 | public void onAttach(Context context) { 34 | super.onAttach(context); 35 | if (context instanceof onSpeechListener) { 36 | mOnSpeechListener = (onSpeechListener) context; 37 | } 38 | } 39 | 40 | @Override 41 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 42 | View view = inflater.inflate(R.layout.fragment_detail, container, false); 43 | TextView tvExample = (TextView) view.findViewById(R.id.tv_exam); 44 | TextView tvKey = (TextView) view.findViewById(R.id.tv_key); 45 | TextView tvPhono = (TextView) view.findViewById(R.id.tv_phono); 46 | TextView tvTrans = (TextView) view.findViewById(R.id.tv_trans); 47 | final Word word = getArguments().getParcelable(Const.WORD_KEY); 48 | mImageView = (ImageView) view.findViewById(R.id.icon_speech); 49 | mImageView.setOnClickListener(new View.OnClickListener() { 50 | @Override 51 | public void onClick(View v) { 52 | if (mOnSpeechListener != null) { 53 | mOnSpeechListener.speech(word); 54 | } 55 | } 56 | }); 57 | if (word != null) { 58 | tvExample.setText(word.getExample()); 59 | tvKey.setText(word.getKey()); 60 | tvPhono.setText("[" + word.getPhono() + "]"); 61 | tvTrans.setText(word.getTrans()); 62 | } 63 | return view; 64 | } 65 | 66 | public void setSpeakImg(int resId) { 67 | mImageView.setImageResource(resId); 68 | } 69 | 70 | @Override 71 | public void onDetach() { 72 | super.onDetach(); 73 | mOnSpeechListener = null; 74 | } 75 | 76 | public interface onSpeechListener { 77 | void speech(Word word); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/pojo/Word.java: -------------------------------------------------------------------------------- 1 | package com.silence.pojo; 2 | 3 | import android.os.Parcel; 4 | import android.os.Parcelable; 5 | 6 | /** 7 | * Created by Silence on 2016/2/8 0008. 8 | */ 9 | public class Word implements Parcelable { 10 | //Word_Id, Word_Key, Word_Phono, Word_Trans, Word_Example, Word_Unit; 11 | private int mId; 12 | private String mKey; 13 | private String mPhono; 14 | private String mTrans; 15 | private String mExample; 16 | private int mUnit; 17 | 18 | public Word() { 19 | } 20 | 21 | public Word(int id, String key, String phono, String trans, String example, int unit) { 22 | mId = id; 23 | mKey = key; 24 | mPhono = phono; 25 | mTrans = trans; 26 | mExample = example; 27 | mUnit = unit; 28 | } 29 | 30 | public int getId() { 31 | return mId; 32 | } 33 | 34 | public void setId(int id) { 35 | mId = id; 36 | } 37 | 38 | public String getKey() { 39 | return mKey; 40 | } 41 | 42 | public void setKey(String key) { 43 | mKey = key; 44 | } 45 | 46 | public String getPhono() { 47 | return mPhono; 48 | } 49 | 50 | public void setPhono(String phono) { 51 | mPhono = phono; 52 | } 53 | 54 | public String getTrans() { 55 | return mTrans; 56 | } 57 | 58 | public void setTrans(String trans) { 59 | mTrans = trans; 60 | } 61 | 62 | public String getExample() { 63 | return mExample; 64 | } 65 | 66 | public void setExample(String example) { 67 | mExample = example; 68 | } 69 | 70 | public int getUnit() { 71 | return mUnit; 72 | } 73 | 74 | public void setUnit(int unit) { 75 | mUnit = unit; 76 | } 77 | 78 | @Override 79 | public int describeContents() { 80 | return 0; 81 | } 82 | 83 | @Override 84 | public void writeToParcel(Parcel dest, int flags) { 85 | dest.writeInt(this.mId); 86 | dest.writeString(this.mKey); 87 | dest.writeString(this.mPhono); 88 | dest.writeString(this.mTrans); 89 | dest.writeString(this.mExample); 90 | dest.writeInt(this.mUnit); 91 | } 92 | 93 | protected Word(Parcel in) { 94 | this.mId = in.readInt(); 95 | this.mKey = in.readString(); 96 | this.mPhono = in.readString(); 97 | this.mTrans = in.readString(); 98 | this.mExample = in.readString(); 99 | this.mUnit = in.readInt(); 100 | } 101 | 102 | public static final Parcelable.Creator CREATOR = new Parcelable.Creator() { 103 | public Word createFromParcel(Parcel source) { 104 | return new Word(source); 105 | } 106 | 107 | public Word[] newArray(int size) { 108 | return new Word[size]; 109 | } 110 | }; 111 | } 112 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/adapter/UnitAdapter.java: -------------------------------------------------------------------------------- 1 | package com.silence.adapter; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.BaseAdapter; 8 | import android.widget.LinearLayout; 9 | import android.widget.TextView; 10 | 11 | import com.andraskindler.quickscroll.Scrollable; 12 | import com.silence.pojo.Unit; 13 | import com.silence.utils.DateUtils; 14 | import com.silence.word.R; 15 | 16 | import java.util.List; 17 | 18 | /** 19 | * Created by Silence on 2016/3/18 0018. 20 | */ 21 | public class UnitAdapter extends BaseAdapter implements Scrollable { 22 | private Context mContext; 23 | private List mUnitList; 24 | 25 | public UnitAdapter(Context context, List units) { 26 | mContext = context; 27 | mUnitList = units; 28 | } 29 | 30 | @Override 31 | public int getCount() { 32 | return mUnitList != null ? mUnitList.size() : 0; 33 | } 34 | 35 | @Override 36 | public Object getItem(int position) { 37 | return mUnitList != null ? mUnitList.get(position) : null; 38 | } 39 | 40 | @Override 41 | public long getItemId(int position) { 42 | return position; 43 | } 44 | 45 | @Override 46 | public View getView(int position, View convertView, ViewGroup parent) { 47 | ViewHolder viewHolder; 48 | if (convertView == null) { 49 | convertView = LayoutInflater.from(mContext).inflate(R.layout.item_category, parent, false); 50 | viewHolder = new ViewHolder(); 51 | viewHolder.linearLayout = (LinearLayout) convertView.findViewById(R.id.item_unit); 52 | viewHolder.tvUnit = (TextView) convertView.findViewById(R.id.tv_unit); 53 | viewHolder.tvTime = (TextView) convertView.findViewById(R.id.tv_time); 54 | convertView.setTag(viewHolder); 55 | } else { 56 | viewHolder = (ViewHolder) convertView.getTag(); 57 | } 58 | Unit unit = mUnitList.get(position); 59 | viewHolder.tvUnit.setText(String.valueOf(unit.getKey())); 60 | viewHolder.tvTime.setText(mContext.getString(R.string.sum_time) + DateUtils.formatTime(unit.getTime())); 61 | if (position % 3 == 1) { 62 | viewHolder.linearLayout.setBackgroundResource(R.drawable.unit_yellow_bg); 63 | } else if (position % 3 == 2) { 64 | viewHolder.linearLayout.setBackgroundResource(R.drawable.unit_red_bg); 65 | } else { 66 | viewHolder.linearLayout.setBackgroundResource(R.drawable.unit_blue_bg); 67 | } 68 | return convertView; 69 | } 70 | 71 | @Override 72 | public String getIndicatorForPosition(int childposition, int groupposition) { 73 | return String.valueOf(mUnitList.get(childposition).getKey()); 74 | } 75 | 76 | @Override 77 | public int getScrollPosition(int childposition, int groupposition) { 78 | return childposition; 79 | } 80 | 81 | static class ViewHolder { 82 | TextView tvUnit; 83 | LinearLayout linearLayout; 84 | TextView tvTime; 85 | } 86 | } 87 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/dao/WordDao.java: -------------------------------------------------------------------------------- 1 | package com.silence.dao; 2 | 3 | import android.content.Context; 4 | import android.database.Cursor; 5 | import android.database.sqlite.SQLiteDatabase; 6 | 7 | import com.silence.pojo.Word; 8 | import com.silence.utils.DBOpenHelper; 9 | 10 | import java.util.ArrayList; 11 | import java.util.List; 12 | 13 | /** 14 | * Created by Silence on 2016/2/8 0008. 15 | */ 16 | public class WordDao { 17 | private DBOpenHelper mDBOpenHelper; 18 | 19 | //Word_Id, Word_Key, Word_Phono, Word_Trans, Word_Example, Word_Unit; 20 | public WordDao(Context context) { 21 | mDBOpenHelper = DBOpenHelper.getInstance(context); 22 | } 23 | 24 | public List getWords(String metaKey, int unitKey) { 25 | List words = null; 26 | String sql = "select Word_Id, Word_Key, Word_Phono, Word_Trans, Word_Example from " + metaKey + " where Word_Unit=?"; 27 | SQLiteDatabase db = mDBOpenHelper.getDatabase(); 28 | Cursor cursor = db.rawQuery(sql, new String[]{String.valueOf(unitKey)}); 29 | if (cursor.moveToFirst()) { 30 | words = new ArrayList<>(cursor.getCount()); 31 | Word word; 32 | do { 33 | int id = cursor.getInt(cursor.getColumnIndex("Word_Id")); 34 | String key = cursor.getString(cursor.getColumnIndex("Word_Key")); 35 | String phono = cursor.getString(cursor.getColumnIndex("Word_Phono")); 36 | String trans = cursor.getString(cursor.getColumnIndex("Word_Trans")); 37 | String exam = cursor.getString(cursor.getColumnIndex("Word_Example")); 38 | word = new Word(id, key, phono, trans, exam, unitKey); 39 | words.add(word); 40 | } while (cursor.moveToNext()); 41 | } 42 | cursor.close(); 43 | return words; 44 | } 45 | 46 | public ArrayList queryWords(String metaKey, String wordKey) { 47 | ArrayList words = null; 48 | String sql = "select Word_Id, Word_Key, Word_Phono, Word_Trans, Word_Example, Word_Unit from " 49 | + metaKey + " where Word_Key like ?;"; 50 | SQLiteDatabase db = mDBOpenHelper.getDatabase(); 51 | Cursor cursor = db.rawQuery(sql, new String[]{wordKey + "%"}); 52 | if (cursor.moveToFirst()) { 53 | words = new ArrayList<>(cursor.getCount()); 54 | Word word; 55 | do { 56 | int id = cursor.getInt(cursor.getColumnIndex("Word_Id")); 57 | String key = cursor.getString(cursor.getColumnIndex("Word_Key")); 58 | String phono = cursor.getString(cursor.getColumnIndex("Word_Phono")); 59 | String trans = cursor.getString(cursor.getColumnIndex("Word_Trans")); 60 | String exam = cursor.getString(cursor.getColumnIndex("Word_Example")); 61 | int unitKey = cursor.getInt(cursor.getColumnIndex("Word_Unit")); 62 | word = new Word(id, key, phono, trans, exam, unitKey); 63 | words.add(word); 64 | } while (cursor.moveToNext()); 65 | } 66 | cursor.close(); 67 | return words; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/fragment/WordListFgt.java: -------------------------------------------------------------------------------- 1 | package com.silence.fragment; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.util.TypedValue; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.AdapterView; 12 | import android.widget.ListView; 13 | 14 | import com.andraskindler.quickscroll.QuickScroll; 15 | import com.silence.adapter.WordAdapter; 16 | import com.silence.dao.WordDao; 17 | import com.silence.pojo.Word; 18 | import com.silence.utils.Const; 19 | import com.silence.word.R; 20 | 21 | import java.util.List; 22 | 23 | /** 24 | * Created by Silence on 2016/2/8 0008. 25 | */ 26 | public class WordListFgt extends Fragment implements AdapterView.OnItemClickListener { 27 | 28 | private onWordClickListener mOnWordClickListener; 29 | 30 | public static WordListFgt newInstance(String metaKey, int unitKey) { 31 | Bundle bundle = new Bundle(); 32 | bundle.putInt(Const.UNIT_KEY, unitKey); 33 | bundle.putString(Const.META_KEY, metaKey); 34 | WordListFgt wordListFgt = new WordListFgt(); 35 | wordListFgt.setArguments(bundle); 36 | return wordListFgt; 37 | } 38 | 39 | @Override 40 | public void onAttach(Context context) { 41 | super.onAttach(context); 42 | if (context instanceof onWordClickListener) { 43 | mOnWordClickListener = (onWordClickListener) context; 44 | } 45 | } 46 | 47 | @Override 48 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 49 | View view = inflater.inflate(R.layout.fragment_list, container, false); 50 | ListView listView = (ListView) view.findViewById(android.R.id.list); 51 | QuickScroll quickScroll = (QuickScroll) view.findViewById(R.id.quickscroll); 52 | WordDao wordDao = new WordDao(getActivity()); 53 | Bundle bundle = getArguments(); 54 | List wordList = wordDao.getWords(bundle.getString(Const.META_KEY), bundle.getInt(Const.UNIT_KEY)); 55 | WordAdapter wordAdapter = new WordAdapter(getActivity(), wordList); 56 | listView.setAdapter(wordAdapter); 57 | listView.setOnItemClickListener(this); 58 | quickScroll.init(QuickScroll.TYPE_POPUP_WITH_HANDLE, listView, wordAdapter, QuickScroll.STYLE_HOLO); 59 | quickScroll.setFixedSize(1); 60 | quickScroll.setPopupColor(QuickScroll.BLUE_LIGHT, QuickScroll.BLUE_LIGHT_SEMITRANSPARENT, 1, Color.WHITE, 1); 61 | quickScroll.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 42); 62 | return view; 63 | } 64 | 65 | @Override 66 | public void onDetach() { 67 | super.onDetach(); 68 | mOnWordClickListener = null; 69 | } 70 | 71 | @Override 72 | public void onItemClick(AdapterView> parent, View view, int position, long id) { 73 | if (mOnWordClickListener != null) { 74 | mOnWordClickListener.getWordList(getArguments().getString(Const.META_KEY), 75 | getArguments().getInt(Const.UNIT_KEY), position); 76 | } 77 | } 78 | 79 | public interface onWordClickListener { 80 | void getWordList(String metaKey, int unitKey, int wordKey); 81 | } 82 | } 83 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/activity/SplashActivity.java: -------------------------------------------------------------------------------- 1 | package com.silence.activity; 2 | 3 | import android.content.Intent; 4 | import android.content.SharedPreferences; 5 | import android.database.Cursor; 6 | import android.database.sqlite.SQLiteDatabase; 7 | import android.os.AsyncTask; 8 | import android.os.Bundle; 9 | import android.preference.PreferenceManager; 10 | import android.support.v7.app.AppCompatActivity; 11 | 12 | import com.iflytek.cloud.SpeechConstant; 13 | import com.iflytek.cloud.SpeechUtility; 14 | import com.silence.utils.Const; 15 | import com.silence.utils.DBOpenHelper; 16 | import com.silence.utils.FileUtils; 17 | import com.silence.word.R; 18 | 19 | import java.util.Timer; 20 | import java.util.TimerTask; 21 | 22 | public class SplashActivity extends AppCompatActivity { 23 | 24 | @Override 25 | protected void onCreate(Bundle savedInstanceState) { 26 | super.onCreate(savedInstanceState); 27 | setContentView(R.layout.activity_splash); 28 | SpeechUtility.createUtility(this, SpeechConstant.APPID + "=*****"); 29 | SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 30 | boolean exist = sharedPreferences.getBoolean(Const.SP_KEY, false); 31 | if (!exist) { 32 | sharedPreferences.edit().putBoolean(Const.SP_KEY, true).apply(); 33 | new FileTask().execute(); 34 | } else { 35 | TimerTask task = new TimerTask() { 36 | @Override 37 | public void run() { 38 | startMain(); 39 | } 40 | }; 41 | Timer timer = new Timer(); 42 | timer.schedule(task, Const.DELAY_TIME); 43 | } 44 | } 45 | 46 | private void startMain() { 47 | Intent intent = new Intent(SplashActivity.this, MainActivity.class); 48 | startActivity(intent); 49 | finish(); 50 | overridePendingTransition(android.R.anim.fade_in, android.R.anim.fade_out); 51 | } 52 | 53 | private void initTable() { 54 | DBOpenHelper dbOpenHelper = DBOpenHelper.getInstance(this); 55 | SQLiteDatabase database = dbOpenHelper.getDatabase(); 56 | database.execSQL("create table if not exists TABLE_UNIT (" + 57 | "Unit_Key integer not null," + 58 | "Unit_Time integer not null default 0," + 59 | "Cate_Key text references TABLE_META(Meta_Key)" + 60 | ");"); 61 | for (String metaKey : Const.META_KEYS) { 62 | Cursor cursor = database.rawQuery("select Meta_UnitCount from TABLE_META where Meta_Key=?;" 63 | , new String[]{metaKey}); 64 | if (cursor.moveToFirst()) { 65 | int count = cursor.getInt(cursor.getColumnIndex("Meta_UnitCount")); 66 | for (int i = 1; i <= count; i++) { 67 | database.execSQL("insert into TABLE_UNIT (Unit_Key,Unit_Time,Cate_Key) " + 68 | "values(?,?,?);", new Object[]{i, 0, metaKey}); 69 | } 70 | } 71 | cursor.close(); 72 | } 73 | } 74 | 75 | private class FileTask extends AsyncTask { 76 | @Override 77 | protected Void doInBackground(Void... params) { 78 | FileUtils.writeData(SplashActivity.this); 79 | initTable(); 80 | return null; 81 | } 82 | 83 | @Override 84 | protected void onPostExecute(Void aVoid) { 85 | super.onPostExecute(aVoid); 86 | startMain(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/utils/WavWriter.java: -------------------------------------------------------------------------------- 1 | package com.silence.utils; 2 | 3 | import java.io.File; 4 | import java.io.IOException; 5 | import java.io.RandomAccessFile; 6 | 7 | public class WavWriter { 8 | /** 9 | * constant define 10 | */ 11 | private static final int SIZE_OF_WAVE_HEADER = 44; 12 | private static final String CHUNK_ID = "RIFF"; 13 | private static final String FORMAT = "WAVE"; 14 | private static final String SUB_CHUNK1_ID = "fmt "; 15 | private static final int SUB_CHUNK1_SIZE = 16; 16 | private static final String SUB_CHUNK2_ID = "data"; 17 | private static final short FORMAT_PCM = 1; // Indicates PCM format. 18 | private static final short DEFAULT_NUM_CHANNELS = 1; 19 | private static final short DEFAULT_BITS_PER_SAMPLE = 16; 20 | 21 | /** 22 | * member properties 23 | */ 24 | private RandomAccessFile mInternalWriter; 25 | private short mNumChannels; 26 | private int mSampleRate; 27 | private short mBitsPerSample; 28 | 29 | public WavWriter(File file, int sample) throws IOException { 30 | init(file, DEFAULT_NUM_CHANNELS, sample, DEFAULT_BITS_PER_SAMPLE); 31 | } 32 | 33 | private boolean init(File file, short numChannels, int sampleRate, short bitsPerSample) throws IOException { 34 | if (null == file) { 35 | return false; 36 | } 37 | mInternalWriter = new RandomAccessFile(file, "rw"); 38 | mNumChannels = numChannels; 39 | mSampleRate = sampleRate; 40 | mBitsPerSample = bitsPerSample; 41 | byte[] buffer = new byte[SIZE_OF_WAVE_HEADER]; 42 | mInternalWriter.write(buffer); 43 | return true; 44 | } 45 | 46 | public void write(byte[] buffer) throws IOException { 47 | mInternalWriter.write(buffer); 48 | } 49 | 50 | public void writeChars(String val) throws IOException { 51 | for (int i = 0; i < val.length(); i++) { 52 | mInternalWriter.write(val.charAt(i)); 53 | } 54 | } 55 | 56 | public void writeInt(int val) throws IOException { 57 | mInternalWriter.write(val >> 0); 58 | mInternalWriter.write(val >> 8); 59 | mInternalWriter.write(val >> 16); 60 | mInternalWriter.write(val >> 24); 61 | } 62 | 63 | public void writeShort(short val) throws IOException { 64 | mInternalWriter.write(val >> 0); 65 | mInternalWriter.write(val >> 8); 66 | } 67 | 68 | public int getDataSize() throws IOException { 69 | return (int) (mInternalWriter.length() - SIZE_OF_WAVE_HEADER); 70 | } 71 | 72 | public void writeHeader() throws IOException { 73 | /* RIFF header */ 74 | mInternalWriter.seek(0); 75 | writeChars(CHUNK_ID); 76 | 77 | writeInt(36 + getDataSize()); 78 | writeChars(FORMAT); 79 | 80 | /** format chunk */ 81 | writeChars(SUB_CHUNK1_ID); 82 | writeInt(SUB_CHUNK1_SIZE); 83 | writeShort(FORMAT_PCM); 84 | writeShort(mNumChannels); 85 | writeInt(mSampleRate); 86 | 87 | writeInt(mNumChannels * mSampleRate * mBitsPerSample / 8); 88 | writeShort((short) (mNumChannels * mBitsPerSample / 8)); 89 | writeShort(mBitsPerSample); 90 | 91 | /** data chunk */ 92 | writeChars(SUB_CHUNK2_ID); 93 | writeInt(getDataSize()); 94 | } 95 | 96 | public void close() throws IOException { 97 | if (mInternalWriter != null) { 98 | mInternalWriter.close(); 99 | mInternalWriter = null; 100 | } 101 | } 102 | } 103 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_detail.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 20 | 21 | 32 | 33 | 42 | 43 | 53 | 54 | 68 | 69 | 79 | 80 | 96 | 97 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/fragment/UnitListFgt.java: -------------------------------------------------------------------------------- 1 | package com.silence.fragment; 2 | 3 | import android.content.Context; 4 | import android.graphics.Color; 5 | import android.os.Bundle; 6 | import android.support.v4.app.Fragment; 7 | import android.util.TypedValue; 8 | import android.view.LayoutInflater; 9 | import android.view.View; 10 | import android.view.ViewGroup; 11 | import android.widget.AdapterView; 12 | import android.widget.ListView; 13 | import android.widget.TextView; 14 | 15 | import com.andraskindler.quickscroll.QuickScroll; 16 | import com.silence.adapter.UnitAdapter; 17 | import com.silence.dao.UnitDao; 18 | import com.silence.pojo.Unit; 19 | import com.silence.utils.Const; 20 | import com.silence.utils.DateUtils; 21 | import com.silence.word.R; 22 | 23 | import java.util.List; 24 | 25 | /** 26 | * Created by Silence on 2016/2/8 0008. 27 | */ 28 | public class UnitListFgt extends Fragment implements AdapterView.OnItemClickListener { 29 | 30 | private int mCurUnit = 0; 31 | private View mClickedView; 32 | private UnitDao mUnitDao; 33 | private onUnitClickListener mOnUnitClickListener; 34 | 35 | public static UnitListFgt getInstance(String metaKey) { 36 | Bundle bundle = new Bundle(); 37 | bundle.putString(Const.META_KEY, metaKey); 38 | UnitListFgt unitListFgt = new UnitListFgt(); 39 | unitListFgt.setArguments(bundle); 40 | return unitListFgt; 41 | } 42 | 43 | @Override 44 | public void onAttach(Context context) { 45 | super.onAttach(context); 46 | if (context instanceof onUnitClickListener) { 47 | mOnUnitClickListener = (onUnitClickListener) context; 48 | } 49 | } 50 | 51 | @Override 52 | public void onStart() { 53 | super.onStart(); 54 | if (mCurUnit != 0 && mClickedView != null) { 55 | long curTime = mUnitDao.getTime(getArguments().getString(Const.META_KEY), 56 | mCurUnit); 57 | TextView textView = (TextView) mClickedView.findViewById(R.id.tv_time); 58 | String text = getString(R.string.sum_time) + DateUtils.formatTime(curTime); 59 | textView.setText(text); 60 | } 61 | } 62 | 63 | @Override 64 | public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { 65 | View view = inflater.inflate(R.layout.fragment_list, container, false); 66 | QuickScroll quickScroll = (QuickScroll) view.findViewById(R.id.quickscroll); 67 | ListView listView = (ListView) view.findViewById(android.R.id.list); 68 | listView.setOnItemClickListener(this); 69 | listView.setDivider(getResources().getDrawable(R.mipmap.word_line)); 70 | listView.setDividerHeight((int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 71 | 1, getActivity().getResources().getDisplayMetrics())); 72 | mUnitDao = new UnitDao(getActivity()); 73 | List units = mUnitDao.getUnits(getArguments().getString(Const.META_KEY)); 74 | UnitAdapter unitAdapter = new UnitAdapter(getActivity(), units); 75 | listView.setAdapter(unitAdapter); 76 | quickScroll.init(QuickScroll.TYPE_POPUP_WITH_HANDLE, listView, unitAdapter, QuickScroll.STYLE_HOLO); 77 | quickScroll.setFixedSize(2); 78 | quickScroll.setPopupColor(QuickScroll.BLUE_LIGHT, QuickScroll.BLUE_LIGHT_SEMITRANSPARENT, 1, Color.WHITE, 1); 79 | quickScroll.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 42); 80 | return view; 81 | } 82 | 83 | @Override 84 | public void onDetach() { 85 | super.onDetach(); 86 | mOnUnitClickListener = null; 87 | } 88 | 89 | @Override 90 | public void onItemClick(AdapterView> parent, View view, int position, long id) { 91 | mCurUnit = position + 1; 92 | mClickedView = view; 93 | if (mOnUnitClickListener != null) { 94 | mOnUnitClickListener.getUnit((Unit) parent.getItemAtPosition(position)); 95 | } 96 | } 97 | 98 | public interface onUnitClickListener { 99 | void getUnit(Unit unit); 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/adapter/CommonAdapter.java: -------------------------------------------------------------------------------- 1 | package com.silence.adapter; 2 | 3 | import android.content.Context; 4 | import android.graphics.BitmapFactory; 5 | import android.graphics.drawable.Drawable; 6 | import android.util.SparseArray; 7 | import android.view.LayoutInflater; 8 | import android.view.View; 9 | import android.view.ViewGroup; 10 | import android.widget.BaseAdapter; 11 | import android.widget.ImageView; 12 | import android.widget.TextView; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | /** 18 | * Created by Jay on 2015/9/22 0022. 19 | */ 20 | public abstract class CommonAdapter extends BaseAdapter { 21 | 22 | private List mData; 23 | private int mLayoutRes; //布局id 24 | 25 | 26 | public CommonAdapter() { 27 | } 28 | 29 | public CommonAdapter(List mData, int mLayoutRes) { 30 | this.mData = mData; 31 | this.mLayoutRes = mLayoutRes; 32 | } 33 | 34 | @Override 35 | public int getCount() { 36 | return mData != null ? mData.size() : 0; 37 | } 38 | 39 | @Override 40 | public T getItem(int position) { 41 | return mData.get(position); 42 | } 43 | 44 | @Override 45 | public long getItemId(int position) { 46 | return position; 47 | } 48 | 49 | @Override 50 | public View getView(int position, View convertView, ViewGroup parent) { 51 | ViewHolder holder = ViewHolder.bind(parent.getContext(), convertView, parent, mLayoutRes 52 | , position); 53 | bindView(holder, getItem(position)); 54 | return holder.getItemView(); 55 | } 56 | 57 | public abstract void bindView(ViewHolder holder, T obj); 58 | 59 | public void setData(List data) { 60 | mData = data; 61 | notifyDataSetChanged(); 62 | } 63 | 64 | //添加一个元素 65 | public void add(T data) { 66 | if (mData == null) { 67 | mData = new ArrayList<>(); 68 | } 69 | mData.add(data); 70 | notifyDataSetChanged(); 71 | } 72 | 73 | //往特定位置,添加一个元素 74 | public void add(int position, T data) { 75 | if (mData == null) { 76 | mData = new ArrayList<>(); 77 | } 78 | mData.add(position, data); 79 | notifyDataSetChanged(); 80 | } 81 | 82 | public void remove(T data) { 83 | if (mData != null) { 84 | mData.remove(data); 85 | } 86 | notifyDataSetChanged(); 87 | } 88 | 89 | public void remove(int position) { 90 | if (mData != null) { 91 | mData.remove(position); 92 | } 93 | notifyDataSetChanged(); 94 | } 95 | 96 | public void clear() { 97 | if (mData != null) { 98 | mData.clear(); 99 | } 100 | notifyDataSetChanged(); 101 | } 102 | 103 | 104 | public static class ViewHolder { 105 | 106 | private SparseArray mViews; //存储ListView 的 item中的View 107 | private View item; //存放convertView 108 | private int position; //游标 109 | private Context context; //Context上下文 110 | 111 | //构造方法,完成相关初始化 112 | private ViewHolder(Context context, ViewGroup parent, int layoutRes) { 113 | mViews = new SparseArray<>(); 114 | this.context = context; 115 | View convertView = LayoutInflater.from(context).inflate(layoutRes, parent, false); 116 | convertView.setTag(this); 117 | item = convertView; 118 | } 119 | 120 | //绑定ViewHolder与item 121 | public static ViewHolder bind(Context context, View convertView, ViewGroup parent, 122 | int layoutRes, int position) { 123 | ViewHolder holder; 124 | if (convertView == null) { 125 | holder = new ViewHolder(context, parent, layoutRes); 126 | } else { 127 | holder = (ViewHolder) convertView.getTag(); 128 | holder.item = convertView; 129 | } 130 | holder.position = position; 131 | return holder; 132 | } 133 | 134 | @SuppressWarnings("unchecked") 135 | public T getView(int id) { 136 | T t = (T) mViews.get(id); 137 | if (t == null) { 138 | t = (T) item.findViewById(id); 139 | mViews.put(id, t); 140 | } 141 | return t; 142 | } 143 | 144 | 145 | /** 146 | * 获取当前条目 147 | */ 148 | public View getItemView() { 149 | return item; 150 | } 151 | 152 | /** 153 | * 获取条目位置 154 | */ 155 | public int getItemPosition() { 156 | return position; 157 | } 158 | 159 | /** 160 | * 设置文字 161 | */ 162 | public ViewHolder setText(int id, CharSequence text) { 163 | View view = getView(id); 164 | if (view instanceof TextView) { 165 | ((TextView) view).setText(text); 166 | } 167 | return this; 168 | } 169 | 170 | /** 171 | * 设置图片 172 | */ 173 | public ViewHolder setImageResource(int id, int drawableRes) { 174 | View view = getView(id); 175 | if (view instanceof ImageView) { 176 | ((ImageView) view).setImageResource(drawableRes); 177 | } else { 178 | view.setBackgroundResource(drawableRes); 179 | } 180 | return this; 181 | } 182 | 183 | /** 184 | * 设置图片 185 | */ 186 | public ViewHolder setImageResource(int id, String path) { 187 | View view = getView(id); 188 | if (view instanceof ImageView) { 189 | ((ImageView) view).setImageBitmap(BitmapFactory.decodeFile(path)); 190 | } else { 191 | view.setBackground(Drawable.createFromPath(path)); 192 | } 193 | return this; 194 | } 195 | 196 | /** 197 | * 设置点击监听 198 | */ 199 | public ViewHolder setOnClickListener(int id, View.OnClickListener listener) { 200 | getView(id).setOnClickListener(listener); 201 | return this; 202 | } 203 | 204 | /** 205 | * 设置可见 206 | */ 207 | public ViewHolder setVisibility(int id, int visible) { 208 | getView(id).setVisibility(visible); 209 | return this; 210 | } 211 | 212 | /** 213 | * 设置标签 214 | */ 215 | public ViewHolder setTag(int id, Object obj) { 216 | getView(id).setTag(obj); 217 | return this; 218 | } 219 | 220 | //其他方法可自行扩展 221 | 222 | } 223 | 224 | } 225 | 226 | -------------------------------------------------------------------------------- /quickscroll/src/main/java/com/andraskindler/quickscroll/ViewHelper.java: -------------------------------------------------------------------------------- 1 | package com.andraskindler.quickscroll; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.view.View; 5 | 6 | import static com.andraskindler.quickscroll.animation.AnimatorProxy.NEEDS_PROXY; 7 | import static com.andraskindler.quickscroll.animation.AnimatorProxy.wrap; 8 | 9 | public final class ViewHelper { 10 | private ViewHelper() { 11 | } 12 | 13 | public static float getAlpha(View view) { 14 | return NEEDS_PROXY ? wrap(view).getAlpha() : Honeycomb.getAlpha(view); 15 | } 16 | 17 | public static void setAlpha(View view, float alpha) { 18 | if (NEEDS_PROXY) { 19 | wrap(view).setAlpha(alpha); 20 | } else { 21 | Honeycomb.setAlpha(view, alpha); 22 | } 23 | } 24 | 25 | public static float getPivotX(View view) { 26 | return NEEDS_PROXY ? wrap(view).getPivotX() : Honeycomb.getPivotX(view); 27 | } 28 | 29 | public static void setPivotX(View view, float pivotX) { 30 | if (NEEDS_PROXY) { 31 | wrap(view).setPivotX(pivotX); 32 | } else { 33 | Honeycomb.setPivotX(view, pivotX); 34 | } 35 | } 36 | 37 | public static float getPivotY(View view) { 38 | return NEEDS_PROXY ? wrap(view).getPivotY() : Honeycomb.getPivotY(view); 39 | } 40 | 41 | public static void setPivotY(View view, float pivotY) { 42 | if (NEEDS_PROXY) { 43 | wrap(view).setPivotY(pivotY); 44 | } else { 45 | Honeycomb.setPivotY(view, pivotY); 46 | } 47 | } 48 | 49 | public static float getRotation(View view) { 50 | return NEEDS_PROXY ? wrap(view).getRotation() : Honeycomb.getRotation(view); 51 | } 52 | 53 | public static void setRotation(View view, float rotation) { 54 | if (NEEDS_PROXY) { 55 | wrap(view).setRotation(rotation); 56 | } else { 57 | Honeycomb.setRotation(view, rotation); 58 | } 59 | } 60 | 61 | public static float getRotationX(View view) { 62 | return NEEDS_PROXY ? wrap(view).getRotationX() : Honeycomb.getRotationX(view); 63 | } 64 | 65 | public static void setRotationX(View view, float rotationX) { 66 | if (NEEDS_PROXY) { 67 | wrap(view).setRotationX(rotationX); 68 | } else { 69 | Honeycomb.setRotationX(view, rotationX); 70 | } 71 | } 72 | 73 | public static float getRotationY(View view) { 74 | return NEEDS_PROXY ? wrap(view).getRotationY() : Honeycomb.getRotationY(view); 75 | } 76 | 77 | public static void setRotationY(View view, float rotationY) { 78 | if (NEEDS_PROXY) { 79 | wrap(view).setRotationY(rotationY); 80 | } else { 81 | Honeycomb.setRotationY(view, rotationY); 82 | } 83 | } 84 | 85 | public static float getScaleX(View view) { 86 | return NEEDS_PROXY ? wrap(view).getScaleX() : Honeycomb.getScaleX(view); 87 | } 88 | 89 | public static void setScaleX(View view, float scaleX) { 90 | if (NEEDS_PROXY) { 91 | wrap(view).setScaleX(scaleX); 92 | } else { 93 | Honeycomb.setScaleX(view, scaleX); 94 | } 95 | } 96 | 97 | public static float getScaleY(View view) { 98 | return NEEDS_PROXY ? wrap(view).getScaleY() : Honeycomb.getScaleY(view); 99 | } 100 | 101 | public static void setScaleY(View view, float scaleY) { 102 | if (NEEDS_PROXY) { 103 | wrap(view).setScaleY(scaleY); 104 | } else { 105 | Honeycomb.setScaleY(view, scaleY); 106 | } 107 | } 108 | 109 | public static float getScrollX(View view) { 110 | return NEEDS_PROXY ? wrap(view).getScrollX() : Honeycomb.getScrollX(view); 111 | } 112 | 113 | public static void setScrollX(View view, int scrollX) { 114 | if (NEEDS_PROXY) { 115 | wrap(view).setScrollX(scrollX); 116 | } else { 117 | Honeycomb.setScrollX(view, scrollX); 118 | } 119 | } 120 | 121 | public static float getScrollY(View view) { 122 | return NEEDS_PROXY ? wrap(view).getScrollY() : Honeycomb.getScrollY(view); 123 | } 124 | 125 | public static void setScrollY(View view, int scrollY) { 126 | if (NEEDS_PROXY) { 127 | wrap(view).setScrollY(scrollY); 128 | } else { 129 | Honeycomb.setScrollY(view, scrollY); 130 | } 131 | } 132 | 133 | public static float getTranslationX(View view) { 134 | return NEEDS_PROXY ? wrap(view).getTranslationX() : Honeycomb.getTranslationX(view); 135 | } 136 | 137 | public static void setTranslationX(View view, float translationX) { 138 | if (NEEDS_PROXY) { 139 | wrap(view).setTranslationX(translationX); 140 | } else { 141 | Honeycomb.setTranslationX(view, translationX); 142 | } 143 | } 144 | 145 | public static float getTranslationY(View view) { 146 | return NEEDS_PROXY ? wrap(view).getTranslationY() : Honeycomb.getTranslationY(view); 147 | } 148 | 149 | public static void setTranslationY(View view, float translationY) { 150 | if (NEEDS_PROXY) { 151 | wrap(view).setTranslationY(translationY); 152 | } else { 153 | Honeycomb.setTranslationY(view, translationY); 154 | } 155 | } 156 | 157 | public static float getX(View view) { 158 | return NEEDS_PROXY ? wrap(view).getX() : Honeycomb.getX(view); 159 | } 160 | 161 | public static void setX(View view, float x) { 162 | if (NEEDS_PROXY) { 163 | wrap(view).setX(x); 164 | } else { 165 | Honeycomb.setX(view, x); 166 | } 167 | } 168 | 169 | public static float getY(View view) { 170 | return NEEDS_PROXY ? wrap(view).getY() : Honeycomb.getY(view); 171 | } 172 | 173 | public static void setY(View view, float y) { 174 | if (NEEDS_PROXY) { 175 | wrap(view).setY(y); 176 | } else { 177 | Honeycomb.setY(view, y); 178 | } 179 | } 180 | 181 | @SuppressLint("NewApi") 182 | private static final class Honeycomb { 183 | static float getAlpha(View view) { 184 | return view.getAlpha(); 185 | } 186 | 187 | static void setAlpha(View view, float alpha) { 188 | view.setAlpha(alpha); 189 | } 190 | 191 | static float getPivotX(View view) { 192 | return view.getPivotX(); 193 | } 194 | 195 | static void setPivotX(View view, float pivotX) { 196 | view.setPivotX(pivotX); 197 | } 198 | 199 | static float getPivotY(View view) { 200 | return view.getPivotY(); 201 | } 202 | 203 | static void setPivotY(View view, float pivotY) { 204 | view.setPivotY(pivotY); 205 | } 206 | 207 | static float getRotation(View view) { 208 | return view.getRotation(); 209 | } 210 | 211 | static void setRotation(View view, float rotation) { 212 | view.setRotation(rotation); 213 | } 214 | 215 | static float getRotationX(View view) { 216 | return view.getRotationX(); 217 | } 218 | 219 | static void setRotationX(View view, float rotationX) { 220 | view.setRotationX(rotationX); 221 | } 222 | 223 | static float getRotationY(View view) { 224 | return view.getRotationY(); 225 | } 226 | 227 | static void setRotationY(View view, float rotationY) { 228 | view.setRotationY(rotationY); 229 | } 230 | 231 | static float getScaleX(View view) { 232 | return view.getScaleX(); 233 | } 234 | 235 | static void setScaleX(View view, float scaleX) { 236 | view.setScaleX(scaleX); 237 | } 238 | 239 | static float getScaleY(View view) { 240 | return view.getScaleY(); 241 | } 242 | 243 | static void setScaleY(View view, float scaleY) { 244 | view.setScaleY(scaleY); 245 | } 246 | 247 | static float getScrollX(View view) { 248 | return view.getScrollX(); 249 | } 250 | 251 | static void setScrollX(View view, int scrollX) { 252 | view.setScrollX(scrollX); 253 | } 254 | 255 | static float getScrollY(View view) { 256 | return view.getScrollY(); 257 | } 258 | 259 | static void setScrollY(View view, int scrollY) { 260 | view.setScrollY(scrollY); 261 | } 262 | 263 | static float getTranslationX(View view) { 264 | return view.getTranslationX(); 265 | } 266 | 267 | static void setTranslationX(View view, float translationX) { 268 | view.setTranslationX(translationX); 269 | } 270 | 271 | static float getTranslationY(View view) { 272 | return view.getTranslationY(); 273 | } 274 | 275 | static void setTranslationY(View view, float translationY) { 276 | view.setTranslationY(translationY); 277 | } 278 | 279 | static float getX(View view) { 280 | return view.getX(); 281 | } 282 | 283 | static void setX(View view, float x) { 284 | view.setX(x); 285 | } 286 | 287 | static float getY(View view) { 288 | return view.getY(); 289 | } 290 | 291 | static void setY(View view, float y) { 292 | view.setY(y); 293 | } 294 | } 295 | } 296 | -------------------------------------------------------------------------------- /quickscroll/src/main/java/com/andraskindler/quickscroll/animation/AnimatorProxy.java: -------------------------------------------------------------------------------- 1 | package com.andraskindler.quickscroll.animation; 2 | 3 | import android.graphics.Camera; 4 | import android.graphics.Matrix; 5 | import android.graphics.RectF; 6 | import android.os.Build; 7 | import android.view.View; 8 | import android.view.animation.Animation; 9 | import android.view.animation.Transformation; 10 | 11 | import java.lang.ref.WeakReference; 12 | import java.util.WeakHashMap; 13 | 14 | /** 15 | * A proxy class to allow for modifying post-3.0 view properties on all pre-3.0 16 | * platforms. DO NOT wrap your views with this class if you 17 | * are using {@code ObjectAnimator} as it will handle that itself. 18 | */ 19 | public final class AnimatorProxy extends Animation { 20 | /** Whether or not the current running platform needs to be proxied. */ 21 | public static final boolean NEEDS_PROXY = Integer.valueOf(Build.VERSION.SDK).intValue() < Build.VERSION_CODES.HONEYCOMB; 22 | 23 | private static final WeakHashMap PROXIES = 24 | new WeakHashMap(); 25 | 26 | /** 27 | * Create a proxy to allow for modifying post-3.0 view properties on all 28 | * pre-3.0 platforms. DO NOT wrap your views if you are 29 | * using {@code ObjectAnimator} as it will handle that itself. 30 | * 31 | * @param view View to wrap. 32 | * @return Proxy to post-3.0 properties. 33 | */ 34 | public static AnimatorProxy wrap(View view) { 35 | AnimatorProxy proxy = PROXIES.get(view); 36 | // This checks if the proxy already exists and whether it still is the animation of the given view 37 | if (proxy == null || proxy != view.getAnimation()) { 38 | proxy = new AnimatorProxy(view); 39 | PROXIES.put(view, proxy); 40 | } 41 | return proxy; 42 | } 43 | 44 | private final WeakReference mView; 45 | private final Camera mCamera = new Camera(); 46 | private boolean mHasPivot; 47 | 48 | private float mAlpha = 1; 49 | private float mPivotX; 50 | private float mPivotY; 51 | private float mRotationX; 52 | private float mRotationY; 53 | private float mRotationZ; 54 | private float mScaleX = 1; 55 | private float mScaleY = 1; 56 | private float mTranslationX; 57 | private float mTranslationY; 58 | 59 | private final RectF mBefore = new RectF(); 60 | private final RectF mAfter = new RectF(); 61 | private final Matrix mTempMatrix = new Matrix(); 62 | 63 | private AnimatorProxy(View view) { 64 | setDuration(0); //perform transformation immediately 65 | setFillAfter(true); //persist transformation beyond duration 66 | view.setAnimation(this); 67 | mView = new WeakReference(view); 68 | } 69 | 70 | public float getAlpha() { 71 | return mAlpha; 72 | } 73 | public void setAlpha(float alpha) { 74 | if (mAlpha != alpha) { 75 | mAlpha = alpha; 76 | View view = mView.get(); 77 | if (view != null) { 78 | view.invalidate(); 79 | } 80 | } 81 | } 82 | public float getPivotX() { 83 | return mPivotX; 84 | } 85 | public void setPivotX(float pivotX) { 86 | if (!mHasPivot || mPivotX != pivotX) { 87 | prepareForUpdate(); 88 | mHasPivot = true; 89 | mPivotX = pivotX; 90 | invalidateAfterUpdate(); 91 | } 92 | } 93 | public float getPivotY() { 94 | return mPivotY; 95 | } 96 | public void setPivotY(float pivotY) { 97 | if (!mHasPivot || mPivotY != pivotY) { 98 | prepareForUpdate(); 99 | mHasPivot = true; 100 | mPivotY = pivotY; 101 | invalidateAfterUpdate(); 102 | } 103 | } 104 | public float getRotation() { 105 | return mRotationZ; 106 | } 107 | public void setRotation(float rotation) { 108 | if (mRotationZ != rotation) { 109 | prepareForUpdate(); 110 | mRotationZ = rotation; 111 | invalidateAfterUpdate(); 112 | } 113 | } 114 | public float getRotationX() { 115 | return mRotationX; 116 | } 117 | public void setRotationX(float rotationX) { 118 | if (mRotationX != rotationX) { 119 | prepareForUpdate(); 120 | mRotationX = rotationX; 121 | invalidateAfterUpdate(); 122 | } 123 | } 124 | public float getRotationY() { 125 | return mRotationY; 126 | } 127 | 128 | public void setRotationY(float rotationY) { 129 | if (mRotationY != rotationY) { 130 | prepareForUpdate(); 131 | mRotationY = rotationY; 132 | invalidateAfterUpdate(); 133 | } 134 | } 135 | public float getScaleX() { 136 | return mScaleX; 137 | } 138 | public void setScaleX(float scaleX) { 139 | if (mScaleX != scaleX) { 140 | prepareForUpdate(); 141 | mScaleX = scaleX; 142 | invalidateAfterUpdate(); 143 | } 144 | } 145 | public float getScaleY() { 146 | return mScaleY; 147 | } 148 | public void setScaleY(float scaleY) { 149 | if (mScaleY != scaleY) { 150 | prepareForUpdate(); 151 | mScaleY = scaleY; 152 | invalidateAfterUpdate(); 153 | } 154 | } 155 | public int getScrollX() { 156 | View view = mView.get(); 157 | if (view == null) { 158 | return 0; 159 | } 160 | return view.getScrollX(); 161 | } 162 | public void setScrollX(int value) { 163 | View view = mView.get(); 164 | if (view != null) { 165 | view.scrollTo(value, view.getScrollY()); 166 | } 167 | } 168 | public int getScrollY() { 169 | View view = mView.get(); 170 | if (view == null) { 171 | return 0; 172 | } 173 | return view.getScrollY(); 174 | } 175 | public void setScrollY(int value) { 176 | View view = mView.get(); 177 | if (view != null) { 178 | view.scrollTo(view.getScrollX(), value); 179 | } 180 | } 181 | 182 | public float getTranslationX() { 183 | return mTranslationX; 184 | } 185 | public void setTranslationX(float translationX) { 186 | if (mTranslationX != translationX) { 187 | prepareForUpdate(); 188 | mTranslationX = translationX; 189 | invalidateAfterUpdate(); 190 | } 191 | } 192 | public float getTranslationY() { 193 | return mTranslationY; 194 | } 195 | public void setTranslationY(float translationY) { 196 | if (mTranslationY != translationY) { 197 | prepareForUpdate(); 198 | mTranslationY = translationY; 199 | invalidateAfterUpdate(); 200 | } 201 | } 202 | public float getX() { 203 | View view = mView.get(); 204 | if (view == null) { 205 | return 0; 206 | } 207 | return view.getLeft() + mTranslationX; 208 | } 209 | public void setX(float x) { 210 | View view = mView.get(); 211 | if (view != null) { 212 | setTranslationX(x - view.getLeft()); 213 | } 214 | } 215 | public float getY() { 216 | View view = mView.get(); 217 | if (view == null) { 218 | return 0; 219 | } 220 | return view.getTop() + mTranslationY; 221 | } 222 | public void setY(float y) { 223 | View view = mView.get(); 224 | if (view != null) { 225 | setTranslationY(y - view.getTop()); 226 | } 227 | } 228 | 229 | private void prepareForUpdate() { 230 | View view = mView.get(); 231 | if (view != null) { 232 | computeRect(mBefore, view); 233 | } 234 | } 235 | private void invalidateAfterUpdate() { 236 | View view = mView.get(); 237 | if (view == null || view.getParent() == null) { 238 | return; 239 | } 240 | 241 | final RectF after = mAfter; 242 | computeRect(after, view); 243 | after.union(mBefore); 244 | 245 | ((View)view.getParent()).invalidate( 246 | (int) Math.floor(after.left), 247 | (int) Math.floor(after.top), 248 | (int) Math.ceil(after.right), 249 | (int) Math.ceil(after.bottom)); 250 | } 251 | 252 | private void computeRect(final RectF r, View view) { 253 | // compute current rectangle according to matrix transformation 254 | final float w = view.getWidth(); 255 | final float h = view.getHeight(); 256 | 257 | // use a rectangle at 0,0 to make sure we don't run into issues with scaling 258 | r.set(0, 0, w, h); 259 | 260 | final Matrix m = mTempMatrix; 261 | m.reset(); 262 | transformMatrix(m, view); 263 | mTempMatrix.mapRect(r); 264 | 265 | r.offset(view.getLeft(), view.getTop()); 266 | 267 | // Straighten coords if rotations flipped them 268 | if (r.right < r.left) { 269 | final float f = r.right; 270 | r.right = r.left; 271 | r.left = f; 272 | } 273 | if (r.bottom < r.top) { 274 | final float f = r.top; 275 | r.top = r.bottom; 276 | r.bottom = f; 277 | } 278 | } 279 | 280 | private void transformMatrix(Matrix m, View view) { 281 | final float w = view.getWidth(); 282 | final float h = view.getHeight(); 283 | final boolean hasPivot = mHasPivot; 284 | final float pX = hasPivot ? mPivotX : w / 2f; 285 | final float pY = hasPivot ? mPivotY : h / 2f; 286 | 287 | final float rX = mRotationX; 288 | final float rY = mRotationY; 289 | final float rZ = mRotationZ; 290 | if ((rX != 0) || (rY != 0) || (rZ != 0)) { 291 | final Camera camera = mCamera; 292 | camera.save(); 293 | camera.rotateX(rX); 294 | camera.rotateY(rY); 295 | camera.rotateZ(-rZ); 296 | camera.getMatrix(m); 297 | camera.restore(); 298 | m.preTranslate(-pX, -pY); 299 | m.postTranslate(pX, pY); 300 | } 301 | 302 | final float sX = mScaleX; 303 | final float sY = mScaleY; 304 | if ((sX != 1.0f) || (sY != 1.0f)) { 305 | m.postScale(sX, sY); 306 | final float sPX = -(pX / w) * ((sX * w) - w); 307 | final float sPY = -(pY / h) * ((sY * h) - h); 308 | m.postTranslate(sPX, sPY); 309 | } 310 | 311 | m.postTranslate(mTranslationX, mTranslationY); 312 | } 313 | 314 | @Override 315 | protected void applyTransformation(float interpolatedTime, Transformation t) { 316 | View view = mView.get(); 317 | if (view != null) { 318 | t.setAlpha(mAlpha); 319 | transformMatrix(t.getMatrix(), view); 320 | } 321 | } 322 | } 323 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/activity/UnitListActivity.java: -------------------------------------------------------------------------------- 1 | package com.silence.activity; 2 | 3 | import android.content.Intent; 4 | import android.media.AudioManager; 5 | import android.media.MediaPlayer; 6 | import android.net.Uri; 7 | import android.os.Bundle; 8 | import android.support.v4.app.FragmentManager; 9 | import android.support.v4.app.FragmentTransaction; 10 | import android.support.v7.app.ActionBar; 11 | import android.support.v7.app.AppCompatActivity; 12 | import android.text.InputType; 13 | import android.text.TextUtils; 14 | import android.view.Menu; 15 | import android.view.MenuItem; 16 | import android.view.View; 17 | import android.widget.SearchView; 18 | 19 | import com.iflytek.cloud.SpeechConstant; 20 | import com.iflytek.cloud.SpeechError; 21 | import com.iflytek.cloud.SpeechSynthesizer; 22 | import com.iflytek.cloud.SynthesizerListener; 23 | import com.silence.dao.WordDao; 24 | import com.silence.fragment.DetailFgt; 25 | import com.silence.fragment.DetailFgt.onSpeechListener; 26 | import com.silence.fragment.SearchFgt; 27 | import com.silence.fragment.UnitListFgt; 28 | import com.silence.pojo.Unit; 29 | import com.silence.pojo.Word; 30 | import com.silence.utils.Const; 31 | import com.silence.utils.WavWriter; 32 | import com.silence.word.R; 33 | 34 | import java.io.File; 35 | import java.io.IOException; 36 | import java.util.ArrayList; 37 | 38 | public class UnitListActivity extends AppCompatActivity implements SearchView.OnQueryTextListener, 39 | SearchFgt.onSearchClickListener, UnitListFgt.onUnitClickListener, onSpeechListener { 40 | private UnitListFgt mUnitListFgt; 41 | private SearchFgt mSearchFgt; 42 | private DetailFgt mDetailFgt; 43 | private SearchView mSearchView; 44 | private String mMetaKey; 45 | private WordDao mWordDao; 46 | private ActionBar mActionBar; 47 | private FragmentManager mFragmentManager; 48 | private SpeechSynthesizer mSynthesizer; 49 | private MediaPlayer mMediaPlayer; 50 | 51 | @Override 52 | protected void onCreate(Bundle savedInstanceState) { 53 | super.onCreate(savedInstanceState); 54 | setContentView(R.layout.activity_list); 55 | mActionBar = getSupportActionBar(); 56 | if (mActionBar != null) { 57 | mActionBar.setDisplayHomeAsUpEnabled(true); 58 | } 59 | mFragmentManager = getSupportFragmentManager(); 60 | mMetaKey = getIntent().getStringExtra(Const.META_KEY); 61 | setActionTitle(); 62 | if (savedInstanceState == null) { 63 | mUnitListFgt = UnitListFgt.getInstance(mMetaKey); 64 | mFragmentManager.beginTransaction().add(R.id.unit_content, mUnitListFgt).commit(); 65 | } 66 | initSpeech(); 67 | initPlayer(); 68 | } 69 | 70 | private void setActionTitle() { 71 | int resId = 0; 72 | switch (mMetaKey) { 73 | case Const.WORDS_NMET: 74 | resId = R.string.nmet; 75 | break; 76 | case Const.WORDS_CET6: 77 | resId = R.string.cet6; 78 | break; 79 | case Const.WORDS_CET4: 80 | resId = R.string.cet4; 81 | break; 82 | case Const.WORDS_GRE: 83 | resId = R.string.gre; 84 | break; 85 | case Const.WORDS_IETSL: 86 | resId = R.string.ietsl; 87 | break; 88 | } 89 | setTitle(resId == 0 ? null : getResources().getString(resId)); 90 | } 91 | 92 | @Override 93 | public boolean onCreateOptionsMenu(Menu menu) { 94 | getMenuInflater().inflate(R.menu.menu_search, menu); 95 | MenuItem item = menu.findItem(R.id.menu_item_search); 96 | mSearchView = (SearchView) item.getActionView(); 97 | if (mSearchView != null) { 98 | mSearchView.setInputType(InputType.TYPE_CLASS_TEXT); 99 | mSearchView.setOnSearchClickListener(new View.OnClickListener() { 100 | @Override 101 | public void onClick(View v) { 102 | mActionBar.setDisplayHomeAsUpEnabled(true); 103 | mWordDao = new WordDao(UnitListActivity.this); 104 | FragmentTransaction transaction = mFragmentManager.beginTransaction(); 105 | transaction.hide(mUnitListFgt); 106 | if (mSearchFgt == null) { 107 | mSearchFgt = SearchFgt.newInstance(mMetaKey); 108 | transaction.add(R.id.unit_content, mSearchFgt); 109 | } else { 110 | transaction.show(mSearchFgt); 111 | } 112 | transaction.commit(); 113 | } 114 | }); 115 | mSearchView.setQueryHint(getString(R.string.search_hint)); 116 | mSearchView.setOnQueryTextListener(this); 117 | } 118 | return true; 119 | } 120 | 121 | @Override 122 | public boolean onOptionsItemSelected(MenuItem item) { 123 | if (item.getItemId() == android.R.id.home) { 124 | FragmentTransaction transaction = mFragmentManager.beginTransaction(); 125 | if (mSearchFgt != null && mSearchFgt.isVisible()) { 126 | hideSearchFgt(transaction); 127 | } else if (mDetailFgt != null && mDetailFgt.isVisible()) { 128 | hideDetailFgt(transaction); 129 | } else { 130 | finish(); 131 | } 132 | transaction.commit(); 133 | return true; 134 | } 135 | return super.onOptionsItemSelected(item); 136 | } 137 | 138 | private void hideDetailFgt(FragmentTransaction transaction) { 139 | setTitle(null); 140 | mSearchView.setIconified(false); 141 | mSearchView.setVisibility(View.VISIBLE); 142 | transaction.remove(mDetailFgt); 143 | transaction.show(mSearchFgt); 144 | } 145 | 146 | private void hideSearchFgt(FragmentTransaction transaction) { 147 | mSearchView.clearFocus(); 148 | mSearchView.setQuery(null, false); 149 | mSearchView.setIconified(true); 150 | setActionTitle(); 151 | transaction.hide(mSearchFgt); 152 | transaction.show(mUnitListFgt); 153 | } 154 | 155 | @Override 156 | public boolean onQueryTextSubmit(String query) { 157 | return false; 158 | } 159 | 160 | @Override 161 | public boolean onQueryTextChange(String newText) { 162 | ArrayList words = null; 163 | if (!TextUtils.isEmpty(newText)) { 164 | words = mWordDao.queryWords(mMetaKey, newText); 165 | } 166 | mSearchFgt.refresh(words); 167 | return true; 168 | } 169 | 170 | @Override 171 | public void getWord(Word word) { 172 | mSearchView.setVisibility(View.INVISIBLE); 173 | mSearchView.setQuery(null, false); 174 | mSearchView.setIconified(true); 175 | setTitle("查询结果"); 176 | FragmentTransaction transaction = mFragmentManager.beginTransaction(); 177 | transaction.hide(mSearchFgt); 178 | mDetailFgt = DetailFgt.newInstance(word); 179 | transaction.setCustomAnimations(android.R.anim.slide_in_left, android.R.anim.slide_out_right); 180 | transaction.add(R.id.unit_content, mDetailFgt); 181 | transaction.commit(); 182 | } 183 | 184 | @Override 185 | public void getUnit(Unit unit) { 186 | Intent intent = new Intent(this, WordListActivity.class); 187 | intent.putExtra(Const.UNIT_KEY, unit); 188 | startActivity(intent); 189 | } 190 | 191 | @Override 192 | public void onBackPressed() { 193 | FragmentTransaction transaction = mFragmentManager.beginTransaction(); 194 | if (mSearchFgt != null && mSearchFgt.isVisible()) { 195 | hideSearchFgt(transaction); 196 | } else if (mDetailFgt != null && mDetailFgt.isVisible()) { 197 | hideDetailFgt(transaction); 198 | } else { 199 | super.onBackPressed(); 200 | } 201 | transaction.commit(); 202 | } 203 | 204 | private void initSpeech() { 205 | mSynthesizer = SpeechSynthesizer.createSynthesizer(this, null); 206 | mSynthesizer.setParameter(SpeechConstant.VOICE_NAME, "catherine"); //设置发音人 207 | mSynthesizer.setParameter(SpeechConstant.SPEED, "50");//设置语速 208 | mSynthesizer.setParameter(SpeechConstant.VOLUME, "80");//设置音量,范围 0~100 209 | mSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置云端 210 | } 211 | 212 | private void initPlayer() { 213 | mMediaPlayer = new MediaPlayer(); 214 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 215 | mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 216 | @Override 217 | public void onPrepared(MediaPlayer mp) { 218 | mMediaPlayer.start(); 219 | } 220 | }); 221 | mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 222 | @Override 223 | public boolean onError(MediaPlayer mp, int what, int extra) { 224 | mMediaPlayer.reset(); 225 | return true; 226 | } 227 | }); 228 | mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 229 | @Override 230 | public void onCompletion(MediaPlayer mp) { 231 | mDetailFgt.setSpeakImg(R.mipmap.icon_speaker_off); 232 | } 233 | }); 234 | } 235 | 236 | @Override 237 | public void speech(Word word) { 238 | mDetailFgt.setSpeakImg(R.mipmap.icon_speaker_on); 239 | String content = word.getKey(); 240 | String path = getExternalCacheDir() + File.separator + "word_" + content + ".pcm"; 241 | final File file = new File(path); 242 | if (file.exists()) { 243 | try { 244 | if (mMediaPlayer.isPlaying()) { 245 | mMediaPlayer.stop(); 246 | } 247 | mMediaPlayer.reset(); 248 | mMediaPlayer.setDataSource(this, Uri.fromFile(file)); 249 | mMediaPlayer.prepareAsync(); 250 | } catch (IOException e) { 251 | e.printStackTrace(); 252 | } 253 | } else { 254 | mSynthesizer.setParameter(SpeechConstant.TTS_AUDIO_PATH, path); 255 | SynthesizerListener synListener = new SynthesizerListener() { 256 | public void onCompleted(SpeechError error) { 257 | if (error == null) { 258 | try { 259 | WavWriter wavWriter = new WavWriter(file, 16000); 260 | wavWriter.writeHeader(); 261 | wavWriter.close(); 262 | } catch (IOException e) { 263 | e.printStackTrace(); 264 | } 265 | mDetailFgt.setSpeakImg(R.mipmap.icon_speaker_off); 266 | } 267 | } 268 | 269 | public void onBufferProgress(int percent, int beginPos, int endPos, String info) { 270 | } 271 | 272 | public void onSpeakBegin() { 273 | } 274 | 275 | public void onSpeakPaused() { 276 | } 277 | 278 | public void onSpeakProgress(int percent, int beginPos, int endPos) { 279 | } 280 | 281 | public void onSpeakResumed() { 282 | } 283 | 284 | public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) { 285 | } 286 | }; 287 | mSynthesizer.startSpeaking(content, synListener); 288 | } 289 | } 290 | 291 | @Override 292 | protected void onDestroy() { 293 | super.onDestroy(); 294 | if (mMediaPlayer != null) { 295 | if (mMediaPlayer.isPlaying()) { 296 | mMediaPlayer.stop(); 297 | } 298 | mMediaPlayer.release(); 299 | mMediaPlayer = null; 300 | } 301 | } 302 | } 303 | -------------------------------------------------------------------------------- /app/src/main/java/com/silence/activity/DetailActivity.java: -------------------------------------------------------------------------------- 1 | package com.silence.activity; 2 | 3 | import android.app.AlertDialog; 4 | import android.content.Context; 5 | import android.content.DialogInterface; 6 | import android.content.Intent; 7 | import android.content.SharedPreferences; 8 | import android.graphics.drawable.Drawable; 9 | import android.media.AudioManager; 10 | import android.media.MediaPlayer; 11 | import android.net.Uri; 12 | import android.os.Bundle; 13 | import android.os.Handler; 14 | import android.os.Message; 15 | import android.preference.PreferenceManager; 16 | import android.support.v4.view.ViewPager; 17 | import android.support.v7.app.ActionBar; 18 | import android.support.v7.app.AppCompatActivity; 19 | import android.view.Menu; 20 | import android.view.MenuItem; 21 | import android.view.View; 22 | import android.widget.TextView; 23 | import android.widget.Toast; 24 | 25 | import com.iflytek.cloud.SpeechConstant; 26 | import com.iflytek.cloud.SpeechError; 27 | import com.iflytek.cloud.SpeechSynthesizer; 28 | import com.iflytek.cloud.SynthesizerListener; 29 | import com.silence.adapter.WordPagerAdapter; 30 | import com.silence.dao.UnitDao; 31 | import com.silence.dao.WordDao; 32 | import com.silence.fragment.DetailFgt; 33 | import com.silence.pojo.Word; 34 | import com.silence.utils.Const; 35 | import com.silence.utils.WavWriter; 36 | import com.silence.word.R; 37 | 38 | import java.io.File; 39 | import java.io.IOException; 40 | import java.lang.ref.WeakReference; 41 | import java.util.List; 42 | import java.util.Timer; 43 | import java.util.TimerTask; 44 | 45 | public class DetailActivity extends AppCompatActivity implements View.OnClickListener, 46 | ViewPager.OnPageChangeListener, DetailFgt.onSpeechListener { 47 | private static final int MSG_REFRESH = 0x1; 48 | private int mLevel = 0;// 2, 1, 0, -1, -2分别代表极慢、稍慢、普通、稍快、极快。 49 | private List mWordList; 50 | private int mWordKey; 51 | private TextView tvPlay; 52 | private boolean mIsPlaying = false; 53 | private Timer mTimer; 54 | private PlayHandler mPlayHandler; 55 | private long mTime; 56 | private String mMetaKey; 57 | private int mUnitKey; 58 | private ViewPager mViewPager; 59 | private SpeechSynthesizer mSynthesizer; 60 | private MediaPlayer mMediaPlayer; 61 | private WordPagerAdapter mWordPagerAdapter; 62 | private SharedPreferences mSharedPreferences; 63 | private boolean mIsAutoSpeak; 64 | 65 | @Override 66 | protected void onCreate(Bundle savedInstanceState) { 67 | super.onCreate(savedInstanceState); 68 | setContentView(R.layout.activity_detail); 69 | ActionBar actionBar = getSupportActionBar(); 70 | if (actionBar != null) { 71 | actionBar.setDisplayHomeAsUpEnabled(true); 72 | } 73 | Intent intent = getIntent(); 74 | mMetaKey = intent.getStringExtra(Const.META_KEY); 75 | mUnitKey = intent.getIntExtra(Const.UNIT_KEY, 1); 76 | mWordKey = intent.getIntExtra(Const.WORD_KEY, 1); 77 | WordDao wordDao = new WordDao(this); 78 | mWordList = wordDao.getWords(mMetaKey, mUnitKey); 79 | mPlayHandler = new PlayHandler(this); 80 | initViews(); 81 | initSpeech(); 82 | initPlayer(); 83 | setTitle((mWordKey + 1) + "/" + mWordList.size()); 84 | mSharedPreferences = PreferenceManager.getDefaultSharedPreferences(this); 85 | mIsAutoSpeak = mSharedPreferences.getBoolean(Const.AUTO_SPEAK, true); 86 | if (mIsAutoSpeak) { 87 | speech(mWordList.get(mWordKey)); 88 | } 89 | } 90 | 91 | private void initPlayer() { 92 | mMediaPlayer = new MediaPlayer(); 93 | mMediaPlayer.setAudioStreamType(AudioManager.STREAM_MUSIC); 94 | mMediaPlayer.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 95 | @Override 96 | public void onPrepared(MediaPlayer mp) { 97 | DetailFgt item = (DetailFgt) mWordPagerAdapter.getFragment(mWordKey); 98 | item.setSpeakImg(R.mipmap.icon_speaker_on); 99 | mMediaPlayer.start(); 100 | } 101 | }); 102 | mMediaPlayer.setOnErrorListener(new MediaPlayer.OnErrorListener() { 103 | @Override 104 | public boolean onError(MediaPlayer mp, int what, int extra) { 105 | mMediaPlayer.reset(); 106 | return true; 107 | } 108 | }); 109 | mMediaPlayer.setOnCompletionListener(new MediaPlayer.OnCompletionListener() { 110 | @Override 111 | public void onCompletion(MediaPlayer mp) { 112 | DetailFgt item = (DetailFgt) mWordPagerAdapter.getFragment(mWordKey); 113 | item.setSpeakImg(R.mipmap.icon_speaker_off); 114 | } 115 | }); 116 | } 117 | 118 | @Override 119 | protected void onStart() { 120 | super.onStart(); 121 | mTime = System.currentTimeMillis(); 122 | } 123 | 124 | @Override 125 | protected void onStop() { 126 | super.onStop(); 127 | long readTime = System.currentTimeMillis() - mTime; 128 | UnitDao unitDao = new UnitDao(this); 129 | unitDao.updateTime(mMetaKey, mUnitKey, readTime); 130 | if (mIsPlaying) { 131 | mTimer.cancel(); 132 | } 133 | } 134 | 135 | private void initViews() { 136 | tvPlay = (TextView) findViewById(R.id.tv_play); 137 | tvPlay.setOnClickListener(this); 138 | findViewById(R.id.btn_prev).setOnClickListener(this); 139 | findViewById(R.id.btn_next).setOnClickListener(this); 140 | mViewPager = (ViewPager) findViewById(R.id.viewpager); 141 | mWordPagerAdapter = new WordPagerAdapter(getSupportFragmentManager(), mWordList); 142 | mViewPager.setAdapter(mWordPagerAdapter); 143 | mViewPager.setCurrentItem(mWordKey); 144 | mViewPager.addOnPageChangeListener(this); 145 | } 146 | 147 | private void initSpeech() { 148 | mSynthesizer = SpeechSynthesizer.createSynthesizer(this, null); 149 | mSynthesizer.setParameter(SpeechConstant.VOICE_NAME, "catherine"); //设置发音人 150 | mSynthesizer.setParameter(SpeechConstant.SPEED, "50");//设置语速 151 | mSynthesizer.setParameter(SpeechConstant.VOLUME, "80");//设置音量,范围 0~100 152 | mSynthesizer.setParameter(SpeechConstant.ENGINE_TYPE, SpeechConstant.TYPE_CLOUD); //设置云端 153 | } 154 | 155 | @Override 156 | public void onClick(View v) { 157 | switch (v.getId()) { 158 | case R.id.btn_prev: 159 | if (mIsPlaying) { 160 | pause(); 161 | } 162 | if (mWordKey - 1 < 0) { 163 | Toast.makeText(this, R.string.first_page, Toast.LENGTH_SHORT).show(); 164 | break; 165 | } else { 166 | mWordKey--; 167 | } 168 | mViewPager.setCurrentItem(mWordKey); 169 | break; 170 | case R.id.tv_play: 171 | if (mIsPlaying) { 172 | pause(); 173 | } else { 174 | play(); 175 | } 176 | break; 177 | case R.id.btn_next: 178 | if (mIsPlaying) { 179 | pause(); 180 | } 181 | if (mWordKey + 1 >= mWordList.size()) { 182 | Toast.makeText(this, R.string.last_page, Toast.LENGTH_SHORT).show(); 183 | break; 184 | } else { 185 | mWordKey++; 186 | } 187 | mViewPager.setCurrentItem(mWordKey); 188 | break; 189 | } 190 | } 191 | 192 | @Override 193 | public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { 194 | 195 | } 196 | 197 | @Override 198 | public void onPageSelected(int position) { 199 | mWordKey = position; 200 | setTitle((mWordKey + 1) + "/" + mWordList.size()); 201 | if (mIsAutoSpeak) { 202 | if (mIsPlaying && mLevel < 0) { 203 | Toast.makeText(this, R.string.toast_too_fast, Toast.LENGTH_SHORT).show(); 204 | pause(); 205 | } else { 206 | speech(mWordList.get(mWordKey)); 207 | } 208 | } 209 | } 210 | 211 | @Override 212 | public void onPageScrollStateChanged(int state) { 213 | 214 | } 215 | 216 | @Override 217 | public void speech(Word word) { 218 | String content = word.getKey(); 219 | String path = getExternalCacheDir() + File.separator + "word_" + content + ".pcm"; 220 | final File file = new File(path); 221 | if (file.exists()) { 222 | try { 223 | if (mMediaPlayer.isPlaying()) { 224 | mMediaPlayer.stop(); 225 | } 226 | mMediaPlayer.reset(); 227 | mMediaPlayer.setDataSource(this, Uri.fromFile(file)); 228 | mMediaPlayer.prepareAsync(); 229 | } catch (IOException e) { 230 | e.printStackTrace(); 231 | } 232 | } else { 233 | final DetailFgt item = (DetailFgt) mWordPagerAdapter.getFragment(mWordKey); 234 | mSynthesizer.setParameter(SpeechConstant.TTS_AUDIO_PATH, path); 235 | SynthesizerListener synListener = new SynthesizerListener() { 236 | 237 | public void onCompleted(SpeechError error) { 238 | if (error == null) { 239 | try { 240 | WavWriter wavWriter = new WavWriter(file, 16000); 241 | wavWriter.writeHeader(); 242 | wavWriter.close(); 243 | } catch (IOException e) { 244 | e.printStackTrace(); 245 | } 246 | } else { 247 | Toast.makeText(getApplicationContext(), R.string.toast_connect, Toast.LENGTH_SHORT).show(); 248 | } 249 | item.setSpeakImg(R.mipmap.icon_speaker_off); 250 | } 251 | 252 | public void onBufferProgress(int percent, int beginPos, int endPos, String info) { 253 | item.setSpeakImg(R.mipmap.icon_speaker_on); 254 | } 255 | 256 | public void onSpeakBegin() { 257 | } 258 | 259 | public void onSpeakPaused() { 260 | } 261 | 262 | public void onSpeakProgress(int percent, int beginPos, int endPos) { 263 | } 264 | 265 | public void onSpeakResumed() { 266 | } 267 | 268 | public void onEvent(int arg0, int arg1, int arg2, Bundle arg3) { 269 | } 270 | }; 271 | mSynthesizer.startSpeaking(content, synListener); 272 | } 273 | } 274 | 275 | private static class PlayHandler extends Handler { 276 | private WeakReference mWeakReference; 277 | 278 | public PlayHandler(DetailActivity detailActivity) { 279 | mWeakReference = new WeakReference(detailActivity); 280 | } 281 | 282 | @Override 283 | public void handleMessage(Message msg) { 284 | DetailActivity detailActivity = (DetailActivity) mWeakReference.get(); 285 | if (detailActivity != null) { 286 | if (msg.what == MSG_REFRESH) { 287 | if (detailActivity.mWordKey + 1 > detailActivity.mWordList.size()) { 288 | detailActivity.pause(); 289 | Toast.makeText(detailActivity, R.string.last_page, Toast.LENGTH_SHORT).show(); 290 | } else { 291 | detailActivity.mViewPager.setCurrentItem(detailActivity.mWordKey); 292 | } 293 | } 294 | } 295 | } 296 | } 297 | 298 | private void pause() { 299 | Drawable drawable = getResources().getDrawable(R.drawable.btn_play_selector); 300 | if (drawable != null) { 301 | drawable.setBounds(0, 0, 51, 51); 302 | } 303 | tvPlay.setCompoundDrawables(null, drawable, null, null); 304 | tvPlay.setText(R.string.tv_play); 305 | mIsPlaying = false; 306 | mTimer.cancel(); 307 | } 308 | 309 | private void play() { 310 | Drawable drawable = getResources().getDrawable(R.drawable.btn_pause_selector); 311 | if (drawable != null) { 312 | drawable.setBounds(0, 0, 51, 51); 313 | } 314 | tvPlay.setCompoundDrawables(null, drawable, null, null); 315 | tvPlay.setText(R.string.tv_pause); 316 | mIsPlaying = true; 317 | if (mIsAutoSpeak) { 318 | speech(mWordList.get(mWordKey)); 319 | } 320 | mWordKey -= 1; 321 | TimerTask timerTask = new TimerTask() { 322 | @Override 323 | public void run() { 324 | mWordKey++; 325 | mPlayHandler.sendEmptyMessage(MSG_REFRESH); 326 | } 327 | }; 328 | long period; 329 | switch (mLevel) { 330 | case -2: 331 | period = 500; 332 | break; 333 | case -1: 334 | period = 1500; 335 | break; 336 | case 0: 337 | period = 2500; 338 | break; 339 | case 1: 340 | period = 3500; 341 | break; 342 | case 2: 343 | period = 4500; 344 | break; 345 | default: 346 | period = 2500; 347 | break; 348 | } 349 | mTimer = new Timer(); 350 | mTimer.schedule(timerTask, 0, period); 351 | } 352 | 353 | @Override 354 | protected void onDestroy() { 355 | super.onDestroy(); 356 | mPlayHandler.removeCallbacksAndMessages(null); 357 | if (mMediaPlayer != null) { 358 | if (mMediaPlayer.isPlaying()) { 359 | mMediaPlayer.stop(); 360 | } 361 | mMediaPlayer.release(); 362 | mMediaPlayer = null; 363 | } 364 | } 365 | 366 | @Override 367 | public boolean onCreateOptionsMenu(Menu menu) { 368 | getMenuInflater().inflate(R.menu.menu_setting, menu); 369 | menu.findItem(R.id.menu_item_speak).setChecked(mIsAutoSpeak); 370 | return true; 371 | } 372 | 373 | @Override 374 | public boolean onOptionsItemSelected(MenuItem item) { 375 | if (mIsPlaying) { 376 | pause(); 377 | } 378 | switch (item.getItemId()) { 379 | case android.R.id.home: { 380 | finish(); 381 | } 382 | break; 383 | case R.id.menu_item_speak: { 384 | SharedPreferences.Editor editor = mSharedPreferences.edit(); 385 | if (item.isChecked()) { 386 | item.setChecked(false); 387 | mIsAutoSpeak = false; 388 | editor.putBoolean(Const.AUTO_SPEAK, false); 389 | } else { 390 | item.setChecked(true); 391 | mIsAutoSpeak = true; 392 | editor.putBoolean(Const.AUTO_SPEAK, true); 393 | } 394 | editor.apply(); 395 | } 396 | break; 397 | case R.id.menu_item_speed: { 398 | AlertDialog.Builder builder = new AlertDialog.Builder(this); 399 | builder.setTitle(R.string.select_speed).setSingleChoiceItems(getResources().getStringArray 400 | (R.array.speed_type), mSharedPreferences.getInt(Const.PLAY_SPEED, mLevel) + 2, 401 | new DialogInterface.OnClickListener() { 402 | @Override 403 | public void onClick(DialogInterface dialog, int which) { 404 | mLevel = which - 2; 405 | mSharedPreferences.edit().putInt(Const.PLAY_SPEED, mLevel).apply(); 406 | dialog.dismiss(); 407 | } 408 | }).show(); 409 | } 410 | break; 411 | } 412 | return true; 413 | } 414 | 415 | } -------------------------------------------------------------------------------- /quickscroll/src/main/java/com/andraskindler/quickscroll/QuickScroll.java: -------------------------------------------------------------------------------- 1 | package com.andraskindler.quickscroll; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.content.Context; 5 | import android.graphics.Color; 6 | import android.graphics.drawable.GradientDrawable; 7 | import android.graphics.drawable.StateListDrawable; 8 | import android.os.Build; 9 | import android.util.AttributeSet; 10 | import android.util.TypedValue; 11 | import android.view.Gravity; 12 | import android.view.MotionEvent; 13 | import android.view.View; 14 | import android.view.ViewGroup; 15 | import android.view.ViewGroup.LayoutParams; 16 | import android.view.animation.AlphaAnimation; 17 | import android.view.animation.Animation; 18 | import android.view.animation.Animation.AnimationListener; 19 | import android.widget.*; 20 | import android.widget.AbsListView.OnScrollListener; 21 | 22 | public class QuickScroll extends View { 23 | 24 | // IDs 25 | protected static final int ID_PIN = 512; 26 | protected static final int ID_PIN_TEXT = 513; 27 | // type statics 28 | public static final int TYPE_POPUP = 0; 29 | public static final int TYPE_INDICATOR = 1; 30 | public static final int TYPE_POPUP_WITH_HANDLE = 2; 31 | public static final int TYPE_INDICATOR_WITH_HANDLE = 3; 32 | // style statics 33 | public static final int STYLE_NONE = 0; 34 | public static final int STYLE_HOLO = 1; 35 | // base colors 36 | public static final int GREY_DARK = Color.parseColor("#e0585858"); 37 | public static final int GREY_LIGHT = Color.parseColor("#f0888888"); 38 | public static final int GREY_SCROLLBAR = Color.parseColor("#64404040"); 39 | public static final int BLUE_LIGHT = Color.parseColor("#FF33B5E5"); 40 | public static final int BLUE_LIGHT_SEMITRANSPARENT = Color.parseColor("#8033B5E5"); 41 | protected static final int SCROLLBAR_MARGIN = 10; 42 | // base variables 43 | protected boolean isScrolling; 44 | protected AlphaAnimation fadeInAnimation, fadeOutAnimation; 45 | protected TextView scrollIndicatorTextView; 46 | protected Scrollable scrollable; 47 | protected ListView listView; 48 | protected int groupPosition; 49 | protected int itemCount; 50 | protected int type; 51 | protected boolean isInitialized = false; 52 | protected static final int TEXT_PADDING = 4; 53 | // handlebar variables 54 | protected View handleBar; 55 | // indicator variables 56 | protected RelativeLayout scrollIndicator; 57 | 58 | // default constructors 59 | public QuickScroll(Context context) { 60 | super(context); 61 | } 62 | 63 | public QuickScroll(Context context, AttributeSet attrs) { 64 | super(context, attrs); 65 | } 66 | 67 | public QuickScroll(Context context, AttributeSet attrs, int defStyle) { 68 | super(context, attrs, defStyle); 69 | } 70 | 71 | /** 72 | * Initializing the QuickScroll, this function must be called. 73 | * 74 | * 75 | * @param type the QuickScroll type. Available inputs: QuickScroll.TYPE_POPUP or QuickScroll.TYPE_INDICATOR 76 | * @param list the ListView 77 | * @param scrollable the adapter, must implement Scrollable interface 78 | */ 79 | public void init(final int type, final ListView list, final Scrollable scrollable, final int style) { 80 | if (isInitialized) return; 81 | 82 | this.type = type; 83 | listView = list; 84 | this.scrollable = scrollable; 85 | groupPosition = -1; 86 | fadeInAnimation = new AlphaAnimation(.0f, 1.0f); 87 | fadeInAnimation.setFillAfter(true); 88 | fadeOutAnimation = new AlphaAnimation(1.0f, .0f); 89 | fadeOutAnimation.setFillAfter(true); 90 | fadeOutAnimation.setAnimationListener(new AnimationListener() { 91 | 92 | public void onAnimationStart(Animation animation) { 93 | } 94 | 95 | public void onAnimationRepeat(Animation animation) { 96 | } 97 | 98 | public void onAnimationEnd(Animation animation) { 99 | isScrolling = false; 100 | } 101 | }); 102 | isScrolling = false; 103 | 104 | listView.setOnTouchListener(new OnTouchListener() { 105 | public boolean onTouch(View v, MotionEvent event) { 106 | if (isScrolling && (event.getAction() == MotionEvent.ACTION_MOVE || event.getAction() == MotionEvent.ACTION_DOWN)) { 107 | return true; 108 | } 109 | return false; 110 | } 111 | }); 112 | 113 | final RelativeLayout.LayoutParams containerParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 114 | final RelativeLayout container = new RelativeLayout(getContext()); 115 | container.setBackgroundColor(Color.TRANSPARENT); 116 | containerParams.addRule(RelativeLayout.ALIGN_TOP, getId()); 117 | containerParams.addRule(RelativeLayout.ALIGN_BOTTOM, getId()); 118 | container.setLayoutParams(containerParams); 119 | 120 | if (this.type == TYPE_POPUP || this.type == TYPE_POPUP_WITH_HANDLE) { 121 | scrollIndicatorTextView = new TextView(getContext()); 122 | scrollIndicatorTextView.setTextColor(Color.WHITE); 123 | scrollIndicatorTextView.setVisibility(View.INVISIBLE); 124 | scrollIndicatorTextView.setGravity(Gravity.CENTER); 125 | final RelativeLayout.LayoutParams popupParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 126 | popupParams.addRule(RelativeLayout.CENTER_IN_PARENT); 127 | scrollIndicatorTextView.setLayoutParams(popupParams); 128 | setPopupColor(GREY_LIGHT, GREY_DARK, 1, Color.WHITE, 1); 129 | setTextPadding(TEXT_PADDING, TEXT_PADDING, TEXT_PADDING, TEXT_PADDING); 130 | container.addView(scrollIndicatorTextView); 131 | } else { 132 | scrollIndicator = createPin(); 133 | scrollIndicatorTextView = (TextView) scrollIndicator.findViewById(ID_PIN_TEXT); 134 | (scrollIndicator.findViewById(ID_PIN)).getLayoutParams().width = 25; 135 | container.addView(scrollIndicator); 136 | } 137 | 138 | // setting scrollbar width 139 | final float density = getResources().getDisplayMetrics().density; 140 | getLayoutParams().width = (int) (30 * density); 141 | scrollIndicatorTextView.setTextSize(TypedValue.COMPLEX_UNIT_DIP, 32); 142 | 143 | // scrollbar setup 144 | if (style != STYLE_NONE) { 145 | final RelativeLayout layout = new RelativeLayout(getContext()); 146 | final RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT); 147 | params.addRule(RelativeLayout.ALIGN_LEFT, getId()); 148 | params.addRule(RelativeLayout.ALIGN_TOP, getId()); 149 | params.addRule(RelativeLayout.ALIGN_RIGHT, getId()); 150 | params.addRule(RelativeLayout.ALIGN_BOTTOM, getId()); 151 | layout.setLayoutParams(params); 152 | 153 | final View scrollbar = new View(getContext()); 154 | scrollbar.setBackgroundColor(GREY_SCROLLBAR); 155 | final RelativeLayout.LayoutParams scrollBarParams = new RelativeLayout.LayoutParams(1, LayoutParams.MATCH_PARENT); 156 | scrollBarParams.addRule(RelativeLayout.CENTER_HORIZONTAL); 157 | scrollBarParams.topMargin = SCROLLBAR_MARGIN; 158 | scrollBarParams.bottomMargin = SCROLLBAR_MARGIN; 159 | scrollbar.setLayoutParams(scrollBarParams); 160 | layout.addView(scrollbar); 161 | ViewGroup.class.cast(listView.getParent()).addView(layout); 162 | // creating the handlebar 163 | if (this.type == TYPE_INDICATOR_WITH_HANDLE || this.type == TYPE_POPUP_WITH_HANDLE) { 164 | handleBar = new View(getContext()); 165 | setHandlebarColor(BLUE_LIGHT, BLUE_LIGHT, BLUE_LIGHT_SEMITRANSPARENT); 166 | final RelativeLayout.LayoutParams handleParams = new RelativeLayout.LayoutParams((int) (12 * density), (int) (36 * density)); 167 | handleBar.setLayoutParams(handleParams); 168 | ((RelativeLayout.LayoutParams) handleBar.getLayoutParams()).addRule(RelativeLayout.CENTER_HORIZONTAL); 169 | layout.addView(handleBar); 170 | 171 | listView.setOnScrollListener(new OnScrollListener() { 172 | 173 | public void onScrollStateChanged(AbsListView view, int scrollState) { 174 | } 175 | 176 | public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { 177 | if (!isScrolling && totalItemCount - visibleItemCount > 0) { 178 | moveHandlebar(getHeight() * firstVisibleItem / (totalItemCount - visibleItemCount)); 179 | } 180 | } 181 | }); 182 | } 183 | } 184 | 185 | isInitialized = true; 186 | 187 | ViewGroup.class.cast(listView.getParent()).addView(container); 188 | } 189 | 190 | @Override 191 | public boolean onTouchEvent(MotionEvent event) { 192 | Adapter adapter = listView.getAdapter(); 193 | 194 | if (adapter == null) 195 | return false; 196 | 197 | if (adapter instanceof HeaderViewListAdapter) { 198 | adapter = ((HeaderViewListAdapter) adapter).getWrappedAdapter(); 199 | } 200 | 201 | itemCount = adapter.getCount(); 202 | if (itemCount == 0) 203 | return false; 204 | if (event.getActionMasked() == MotionEvent.ACTION_CANCEL) { 205 | if (type == TYPE_POPUP || type == TYPE_INDICATOR) { 206 | scrollIndicatorTextView.startAnimation(fadeOutAnimation); 207 | } else { 208 | if (type == TYPE_INDICATOR_WITH_HANDLE || type == TYPE_POPUP_WITH_HANDLE) 209 | handleBar.setSelected(false); 210 | scrollIndicator.startAnimation(fadeOutAnimation); 211 | } 212 | } 213 | switch (event.getActionMasked()) { 214 | case MotionEvent.ACTION_DOWN: 215 | if (type == TYPE_INDICATOR || type == TYPE_INDICATOR_WITH_HANDLE) { 216 | scrollIndicator.startAnimation(fadeInAnimation); 217 | scrollIndicator.setPadding(0, 0, getWidth(), 0); 218 | } else 219 | scrollIndicatorTextView.startAnimation(fadeInAnimation); 220 | scroll(event.getY()); 221 | isScrolling = true; 222 | return true; 223 | case MotionEvent.ACTION_MOVE: 224 | scroll(event.getY()); 225 | return true; 226 | case MotionEvent.ACTION_UP: 227 | if (type == TYPE_INDICATOR_WITH_HANDLE || type == TYPE_POPUP_WITH_HANDLE) 228 | handleBar.setSelected(false); 229 | if (type == TYPE_INDICATOR || type == TYPE_INDICATOR_WITH_HANDLE) 230 | scrollIndicator.startAnimation(fadeOutAnimation); 231 | else 232 | scrollIndicatorTextView.startAnimation(fadeOutAnimation); 233 | return true; 234 | default: 235 | return false; 236 | } 237 | } 238 | 239 | @SuppressLint("NewApi") 240 | protected void scroll(final float height) { 241 | if (type == TYPE_INDICATOR || type == TYPE_INDICATOR_WITH_HANDLE) { 242 | float move = height - (scrollIndicator.getHeight() / 2); 243 | 244 | if (move < 0) 245 | move = 0; 246 | else if (move > getHeight() - scrollIndicator.getHeight()) 247 | move = getHeight() - scrollIndicator.getHeight(); 248 | 249 | // scrollIndicator.setTranslationY(move); 250 | ViewHelper.setTranslationY(scrollIndicator, move); 251 | } 252 | 253 | if (type == TYPE_INDICATOR_WITH_HANDLE || type == TYPE_POPUP_WITH_HANDLE) { 254 | handleBar.setSelected(true); 255 | moveHandlebar(height - (handleBar.getHeight() / 2)); 256 | } 257 | 258 | int position = (int) ((height / getHeight()) * itemCount); 259 | if (listView instanceof ExpandableListView) { 260 | final int groupPosition = ExpandableListView.getPackedPositionGroup(((ExpandableListView) listView).getExpandableListPosition(position)); 261 | if (groupPosition != -1) 262 | this.groupPosition = groupPosition; 263 | } 264 | 265 | if (position < 0) 266 | position = 0; 267 | else if (position >= itemCount) 268 | position = itemCount - 1; 269 | scrollIndicatorTextView.setText(scrollable.getIndicatorForPosition(position, groupPosition)); 270 | listView.setSelection(scrollable.getScrollPosition(position, groupPosition)); 271 | } 272 | 273 | @SuppressLint("NewApi") 274 | protected void moveHandlebar(final float where) { 275 | float move = where; 276 | if (move < SCROLLBAR_MARGIN) 277 | move = SCROLLBAR_MARGIN; 278 | else if (move > getHeight() - handleBar.getHeight() - SCROLLBAR_MARGIN) 279 | move = getHeight() - handleBar.getHeight() - SCROLLBAR_MARGIN; 280 | 281 | // handleBar.setTranslationY(move); 282 | ViewHelper.setTranslationY(handleBar, move); 283 | } 284 | 285 | /** 286 | * Sets the fade in and fade out duration of the indicator; default is 150 ms. 287 | * 288 | * 289 | * @param millis the fade duration in milliseconds 290 | */ 291 | public void setFadeDuration(long millis) { 292 | fadeInAnimation.setDuration(millis); 293 | fadeOutAnimation.setDuration(millis); 294 | } 295 | 296 | /** 297 | * Sets the indicator colors, when QuickScroll.TYPE_INDICATOR is selected as type. 298 | * 299 | * 300 | * @param background the background color of the square 301 | * @param tip the background color of the tip triangle 302 | * @param text the color of the text 303 | */ 304 | public void setIndicatorColor(final int background, final int tip, final int text) { 305 | if (type == TYPE_INDICATOR || type == TYPE_INDICATOR_WITH_HANDLE) { 306 | ((Pin) scrollIndicator.findViewById(ID_PIN)).setColor(tip); 307 | scrollIndicatorTextView.setTextColor(text); 308 | scrollIndicatorTextView.setBackgroundColor(background); 309 | } 310 | } 311 | 312 | /** 313 | * Sets the popup colors, when QuickScroll.TYPE_POPUP is selected as type. 314 | * 315 | * 316 | * @param backgroundcolor the background color of the TextView 317 | * @param bordercolor the background color of the border surrounding the TextView 318 | * @param textcolor the color of the text 319 | */ 320 | public void setPopupColor(final int backgroundcolor, final int bordercolor, final int borderwidthDPI, final int textcolor, float cornerradiusDPI) { 321 | 322 | final GradientDrawable popupbackground = new GradientDrawable(); 323 | popupbackground.setCornerRadius(cornerradiusDPI * getResources().getDisplayMetrics().density); 324 | popupbackground.setStroke((int) (borderwidthDPI * getResources().getDisplayMetrics().density), bordercolor); 325 | popupbackground.setColor(backgroundcolor); 326 | 327 | if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) 328 | scrollIndicatorTextView.setBackgroundDrawable(popupbackground); 329 | else 330 | scrollIndicatorTextView.setBackground(popupbackground); 331 | 332 | scrollIndicatorTextView.setTextColor(textcolor); 333 | } 334 | 335 | /** 336 | * Sets the width and height of the TextView containing the indicatortext. Default is WRAP_CONTENT, WRAP_CONTENT. 337 | * 338 | * 339 | * @param widthDP width in DP 340 | * @param heightDP height in DP 341 | */ 342 | public void setSize(final int widthDP, final int heightDP) { 343 | final float density = getResources().getDisplayMetrics().density; 344 | scrollIndicatorTextView.getLayoutParams().width = (int) (widthDP * density); 345 | scrollIndicatorTextView.getLayoutParams().height = (int) (heightDP * density); 346 | } 347 | 348 | /** 349 | * Sets the padding of the TextView containing the indicatortext. Default is 4 dp. 350 | * 351 | * 352 | * @param paddingLeftDP left padding in DP 353 | * @param paddingTopDP top param in DP 354 | * @param paddingBottomDP bottom param in DP 355 | * @param paddingRightDP right param in DP 356 | */ 357 | public void setTextPadding(final int paddingLeftDP, final int paddingTopDP, final int paddingBottomDP, final int paddingRightDP) { 358 | final float density = getResources().getDisplayMetrics().density; 359 | scrollIndicatorTextView.setPadding((int) (paddingLeftDP * density), (int) (paddingTopDP * density), (int) (paddingRightDP * density), (int) (paddingBottomDP * density)); 360 | 361 | } 362 | 363 | /** 364 | * Turns on fixed size for the TextView containing the indicatortext. Do not use with setSize()! This mode looks good if the indicatortext length is fixed, e.g. it's always two characters long. 365 | * 366 | * 367 | * @param sizeEMS number of characters in the indicatortext 368 | */ 369 | public void setFixedSize(final int sizeEMS) { 370 | scrollIndicatorTextView.setEms(sizeEMS); 371 | } 372 | 373 | /** 374 | * Set the textsize of the TextView containing the indicatortext. 375 | * 376 | * @param unit - use TypedValue statics 377 | * @param size - the size according to the selected unit 378 | */ 379 | public void setTextSize(final int unit, final float size) { 380 | scrollIndicatorTextView.setTextSize(unit, size); 381 | } 382 | 383 | /** 384 | * Set the colors of the handlebar. 385 | * 386 | * @param inactive - color of the inactive handlebar 387 | * @param activebase - base color of the active handlebar 388 | * @param activestroke - stroke of the active handlebar 389 | */ 390 | public void setHandlebarColor(final int inactive, final int activebase, final int activestroke) { 391 | if (type == TYPE_INDICATOR_WITH_HANDLE || type == TYPE_POPUP_WITH_HANDLE) { 392 | final float density = getResources().getDisplayMetrics().density; 393 | final GradientDrawable bg_inactive = new GradientDrawable(); 394 | bg_inactive.setCornerRadius(density); 395 | bg_inactive.setColor(inactive); 396 | bg_inactive.setStroke((int) (5 * density), Color.TRANSPARENT); 397 | final GradientDrawable bg_active = new GradientDrawable(); 398 | bg_active.setCornerRadius(density); 399 | bg_active.setColor(activebase); 400 | bg_active.setStroke((int) (5 * density), activestroke); 401 | final StateListDrawable states = new StateListDrawable(); 402 | states.addState(new int[]{android.R.attr.state_selected}, bg_active); 403 | states.addState(new int[]{android.R.attr.state_enabled}, bg_inactive); 404 | 405 | if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN) 406 | handleBar.setBackgroundDrawable(states); 407 | else 408 | handleBar.setBackground(states); 409 | } 410 | } 411 | 412 | protected RelativeLayout createPin() { 413 | final RelativeLayout pinLayout = new RelativeLayout(getContext()); 414 | pinLayout.setVisibility(View.INVISIBLE); 415 | 416 | final Pin pin = new Pin(getContext()); 417 | pin.setId(ID_PIN); 418 | final RelativeLayout.LayoutParams pinParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 419 | pinParams.addRule(RelativeLayout.ALIGN_PARENT_RIGHT); 420 | pinParams.addRule(RelativeLayout.ALIGN_BOTTOM, ID_PIN_TEXT); 421 | pinParams.addRule(RelativeLayout.ALIGN_TOP, ID_PIN_TEXT); 422 | pin.setLayoutParams(pinParams); 423 | pinLayout.addView(pin); 424 | 425 | final TextView indicatorTextView = new TextView(getContext()); 426 | indicatorTextView.setId(ID_PIN_TEXT); 427 | final RelativeLayout.LayoutParams indicatorParams = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); 428 | indicatorParams.addRule(RelativeLayout.LEFT_OF, ID_PIN); 429 | indicatorTextView.setLayoutParams(indicatorParams); 430 | indicatorTextView.setTextColor(Color.WHITE); 431 | indicatorTextView.setGravity(Gravity.CENTER); 432 | indicatorTextView.setBackgroundColor(GREY_LIGHT); 433 | pinLayout.addView(indicatorTextView); 434 | 435 | return pinLayout; 436 | } 437 | 438 | } 439 | --------------------------------------------------------------------------------
5 | 6 | 7 | 8 | 9 | 10 | 11 |