├── .gitignore ├── .idea ├── codeStyles │ └── Project.xml ├── compiler.xml ├── gradle.xml ├── markdown-navigator.xml ├── markdown-navigator │ └── profiles_settings.xml ├── misc.xml └── runConfigurations.xml ├── README.md ├── build.gradle ├── example ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ ├── androidTest │ └── java │ │ └── com │ │ └── avery │ │ └── subtitle │ │ └── ExampleInstrumentedTest.java │ ├── main │ ├── AndroidManifest.xml │ ├── java │ │ └── com │ │ │ └── avery │ │ │ └── subtitle │ │ │ └── example │ │ │ ├── MainActivity.java │ │ │ └── SettingsDialog.java │ └── res │ │ ├── drawable-v24 │ │ └── ic_launcher_foreground.xml │ │ ├── drawable │ │ ├── bg_button.xml │ │ ├── bg_button2.xml │ │ ├── bg_button_color_purple.xml │ │ ├── bg_button_color_red.xml │ │ ├── bg_button_color_white.xml │ │ └── ic_launcher_background.xml │ │ ├── layout │ │ ├── activity_main.xml │ │ └── dialog_settings.xml │ │ ├── mipmap-anydpi-v26 │ │ ├── ic_launcher.xml │ │ └── ic_launcher_round.xml │ │ ├── mipmap-hdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-mdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ ├── mipmap-xxxhdpi │ │ ├── ic_launcher.png │ │ └── ic_launcher_round.png │ │ └── values │ │ ├── colors.xml │ │ ├── strings.xml │ │ └── styles.xml │ └── test │ └── java │ └── com │ └── avery │ └── subtitle │ └── ExampleUnitTest.java ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── screenshot ├── one.png └── two.png ├── settings.gradle └── subtitle ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src ├── androidTest └── java │ └── com │ └── avery │ └── subtitle │ └── ExampleInstrumentedTest.java ├── main ├── AndroidManifest.xml ├── java │ └── com │ │ └── avery │ │ └── subtitle │ │ ├── DefaultSubtitleEngine.java │ │ ├── SubtitleEngine.java │ │ ├── SubtitleFinder.java │ │ ├── SubtitleLoader.java │ │ ├── UIRenderTask.java │ │ ├── cache │ │ └── SubtitleCache.java │ │ ├── exception │ │ └── FatalParsingException.java │ │ ├── format │ │ ├── FormatASS.java │ │ ├── FormatSCC.java │ │ ├── FormatSRT.java │ │ ├── FormatSTL.java │ │ ├── FormatTTML.java │ │ └── TimedTextFileFormat.java │ │ ├── model │ │ ├── Region.java │ │ ├── Style.java │ │ ├── Subtitle.java │ │ ├── Time.java │ │ └── TimedTextObject.java │ │ ├── runtime │ │ ├── AppTaskExecutor.java │ │ ├── DefaultTaskExecutor.java │ │ └── TaskExecutor.java │ │ └── widget │ │ └── SimpleSubtitleView.java └── res │ └── values │ └── strings.xml └── test └── java └── com └── avery └── subtitle └── ExampleUnitTest.java /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/caches 5 | /.idea/libraries 6 | /.idea/modules.xml 7 | /.idea/workspace.xml 8 | /.idea/navEditor.xml 9 | /.idea/assetWizardSettings.xml 10 | .DS_Store 11 | /build 12 | /captures 13 | .externalNativeBuild 14 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 15 | 16 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/compiler.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/gradle.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 14 | 15 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 36 | 37 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | -------------------------------------------------------------------------------- /.idea/markdown-navigator/profiles_settings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 12 | 13 | 14 | 15 | 16 | 18 | -------------------------------------------------------------------------------- /.idea/runConfigurations.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 11 | 12 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | CSDN blog: https://blog.csdn.net/han_han_1/article/details/86747472 2 | 3 | [ ![Download](https://api.bintray.com/packages/averyzhong/AndroidRepo/subtitle-for-android/images/download.svg?version=1.0.6) ](https://bintray.com/averyzhong/AndroidRepo/subtitle-for-android/1.0.6/link) 4 | 5 | # Android外挂字幕组件库(Subtitle For Android) 6 | 7 | 8 | ## 概述 9 | Subtitle For Android 是一个Android平台视频播放多字幕支持库,几乎支持所有的Android版本,可以在需要外挂字幕中的项目集成。支持的字幕格式有:.SRT、.SCC、.ASS、.STL、.TTML格式的字幕文件。集成方式简单,可几行代码就可以使你的播放器支持外挂做字幕的支持 10 | 11 | ## 下载 12 | 13 | ``` 14 | implementation 'com.avery:subtitle:1.0.6' // 最新版本号请看上面"Download"气泡后面的数字 15 | ``` 16 | 17 | > 18 | > 如果Gradle同步出现如下错误: 19 | > Manifest merger failed : uses-sdk:minSdkVersion xx cannot be smaller than version xx declared in library [com.avery:subtitle:x.x.x] 20 | > 21 | >请在`AndroidManifest.xml`中加入`` 22 | > 23 | 24 | ## 怎样使用? 25 | 1. 在播放器布局文件中添加`SimpleSubtitleView` 26 | 27 | ``` 28 | 38 | 39 | ``` 40 | 41 | 2. 绑定`MediaPlayer`到`SimpleSubtitleView` 42 | 43 | ``` 44 | private SimpleSubtitleView mSubtitleView; 45 | 46 | ....省略无关代码..... 47 | 48 | mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 49 | @Override 50 | public void onPrepared(final MediaPlayer mp) { 51 | // 绑定MediaPlayer 52 | mSubtitleView.bindToMediaPlayer(mp); 53 | // 设置字幕 54 | mSubtitleView.setSubtitlePath(SUBTITLE_URL); 55 | } 56 | }); 57 | mVideoView.setVideoURI(Uri.parse(VIDEO_URL)); 58 | 59 | ....省略无关代码..... 60 | 61 | 62 | @Override 63 | protected void onDestroy() { 64 | mSubtitleView.destroy(); // 记得销毁 65 | super.onDestroy(); 66 | } 67 | 68 | ``` 69 | 70 | `SimpleSubtitleView`还有其他与`Activity`生命周期相似的方法:`start()`,`pause()`,`resume()`,`stop()`,`reset()` 可以根据具体集成情况在适当的地方进行调用。 71 | 72 | ## 字幕样式设置 73 | `SimpleSubtitleView`继承自`TextView`,所以`TextView`的所有样式设置都适用于`SimpleSubtitleView`,如设置字幕颜色、字幕大小、字幕对其方式等。 74 | 75 | ## 注意!!! 76 | > 1. 最好在`MediaPlayer`初始化完成后才能调用`SimpleSubtitleView.setSubtitlePath()`方法,最好的时机是在MediaPlayer的`onPrepared`回调方法里调用`SimpleSubtitleView.setSubtitlePath()`。 77 | > 2. 最好在`MediaPlayer`销毁之前先销毁`SimpleSubtitleView`,即调用`SimpleSubtitleView.destroy()`,最好的时机是在调用`MediaPlayer.release()`方法前先调用调用`SimpleSubtitleView.destroy()`。 78 | 79 | 80 | ## 自定义字幕显示控件 81 | 如果不想使用提供的`SimpleSubtitleView`控件,你还可以轻松自定义你自己的显示控件,只需通过 82 | `DefaultSubtitleEngine`来辅助就能办到 83 | 84 | ``` 85 | .... 86 | private SubtitleEngine mSubtitleEngine = new DefaultSubtitleEngine(); 87 | 88 | mSubtitleEngine.setOnSubtitlePreparedListener(new OnSubtitlePreparedListener() { 89 | @Override 90 | public void onSubtitlePrepared(@Nullable final List subtitles) { 91 | // 启动字幕刷新任务 92 | mSubtitleEngine.start(); 93 | } 94 | }); 95 | 96 | mSubtitleEngine.setOnSubtitleChangeListener(new OnSubtitleChangeListener() { 97 | @Override 98 | public void onSubtitleChanged(@Nullable final Subtitle subtitle) { 99 | // 拿到Subtitle对象来刷新你自定义过的字幕显示控件,注意subtitle可能为空 100 | // 当subtitle为空时,你应该清除自定义控件已显示的字幕显示 101 | ....... 102 | } 103 | }); 104 | .... 105 | ``` 106 | 107 | 自定义的最后一步就是通过`DefaultSubtitleEngine`的生命周期相应方法:`start()`,`pause()`,`resume()`,`stop()`,`reset()`处理好控件的生命周期,以免导致bug。 108 | 109 | ## 快照 110 | ![](screenshot/one.png) 111 | ![](screenshot/two.png) 112 | 113 | ## License 114 | ``` 115 | Copyright 2019 AveryZhong 116 | 117 | Licensed under the Apache License, Version 2.0 (the "License"); 118 | you may not use this file except in compliance with the License. 119 | You may obtain a copy of the License at 120 | 121 | http://www.apache.org/licenses/LICENSE-2.0 122 | 123 | Unless required by applicable law or agreed to in writing, software 124 | distributed under the License is distributed on an "AS IS" BASIS, 125 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 126 | See the License for the specific language governing permissions and 127 | limitations under the License. 128 | ``` 129 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | ext { 5 | // Sdk and tools 6 | compileSdkVersion = 28 7 | minSdkVersion = 14 8 | targetSdkVersion = 28 9 | 10 | gradleVersion = '3.3.0' 11 | supportLibraryVersion = '20.0.0' 12 | constraintLayoutVersion = '1.1.3' 13 | junitVersion = '4.12' 14 | testRunnerVersion = '1.0.2' 15 | espressoCoreVersion = '3.0.2' 16 | androidMavenGradlePluginVersion = '2.1' 17 | gradleBintrayPluginVersion = '1.7.3' 18 | } 19 | repositories { 20 | google() 21 | jcenter() 22 | 23 | } 24 | dependencies { 25 | classpath "com.android.tools.build:gradle:$gradleVersion" 26 | classpath "com.github.dcendents:android-maven-gradle-plugin:$androidMavenGradlePluginVersion" 27 | classpath "com.jfrog.bintray.gradle:gradle-bintray-plugin:$gradleBintrayPluginVersion" 28 | 29 | // NOTE: Do not place your application dependencies here; they belong 30 | // in the individual module build.gradle files 31 | } 32 | } 33 | 34 | allprojects { 35 | repositories { 36 | google() 37 | jcenter() 38 | 39 | } 40 | } 41 | 42 | task clean(type: Delete) { 43 | delete rootProject.buildDir 44 | } 45 | -------------------------------------------------------------------------------- /example/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /example/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion rootProject.compileSdkVersion 5 | defaultConfig { 6 | applicationId "com.avery.subtitle.example" 7 | minSdkVersion rootProject.minSdkVersion 8 | targetSdkVersion rootProject.targetSdkVersion 9 | versionCode 1 10 | versionName "1.0" 11 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | implementation fileTree(include: ['*.jar'], dir: 'libs') 23 | implementation "com.android.support:appcompat-v7:28.0.0" 24 | implementation "com.android.support.constraint:constraint-layout:$constraintLayoutVersion" 25 | testImplementation "junit:junit:$junitVersion" 26 | androidTestImplementation "com.android.support.test:runner:$testRunnerVersion" 27 | androidTestImplementation "com.android.support.test.espresso:espresso-core:$espressoCoreVersion" 28 | implementation project(':subtitle') 29 | } 30 | -------------------------------------------------------------------------------- /example/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile 22 | -------------------------------------------------------------------------------- /example/src/androidTest/java/com/avery/subtitle/ExampleInstrumentedTest.java: -------------------------------------------------------------------------------- 1 | package com.avery.subtitle; 2 | 3 | import android.content.Context; 4 | import android.support.test.InstrumentationRegistry; 5 | import android.support.test.runner.AndroidJUnit4; 6 | 7 | import org.junit.Test; 8 | import org.junit.runner.RunWith; 9 | 10 | import static org.junit.Assert.*; 11 | 12 | /** 13 | * Instrumented test, which will execute on an Android device. 14 | * 15 | * @see Testing documentation 16 | */ 17 | @RunWith(AndroidJUnit4.class) 18 | public class ExampleInstrumentedTest { 19 | @Test 20 | public void useAppContext() { 21 | // Context of the app under test. 22 | Context appContext = InstrumentationRegistry.getTargetContext(); 23 | 24 | assertEquals("com.avery.subtitle", appContext.getPackageName()); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /example/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | 7 | 8 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /example/src/main/java/com/avery/subtitle/example/MainActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) of Avery 3 | * 4 | * _ooOoo_ 5 | * o8888888o 6 | * 88" . "88 7 | * (| -_- |) 8 | * O\ = /O 9 | * ____/`- -'\____ 10 | * .' \\| |// `. 11 | * / \\||| : |||// \ 12 | * / _||||| -:- |||||- \ 13 | * | | \\\ - /// | | 14 | * | \_| ''\- -/'' | | 15 | * \ .-\__ `-` ___/-. / 16 | * ___`. .' /- -.- -\ `. . __ 17 | * ."" '< `.___\_<|>_/___.' >'"". 18 | * | | : `- \`.;`\ _ /`;.`/ - ` : | | 19 | * \ \ `-. \_ __\ /__ _/ .-` / / 20 | * ======`-.____`-.___\_____/___.-`____.-'====== 21 | * `=- -=' 22 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 23 | * Buddha bless, there will never be bug!!! 24 | */ 25 | 26 | package com.avery.subtitle.example; 27 | 28 | import android.content.Context; 29 | import android.graphics.Color; 30 | import android.media.MediaPlayer; 31 | import android.net.Uri; 32 | import android.os.Bundle; 33 | import android.support.v7.app.AppCompatActivity; 34 | import android.view.Gravity; 35 | import android.view.View; 36 | import android.widget.Button; 37 | import android.widget.RelativeLayout; 38 | import android.widget.TextView; 39 | import android.widget.Toast; 40 | import android.widget.VideoView; 41 | 42 | import com.avery.subtitle.widget.SimpleSubtitleView; 43 | 44 | 45 | public class MainActivity extends AppCompatActivity implements View.OnClickListener { 46 | 47 | private static final String VIDEO_URL = "http://172.16.201.228/movie/Ultra.Pulpe.2018.B.Mandico.DVDRip.Cinetik.mkv"; 48 | private static final String SUBTITLE_URL = "http://172.16.201.228/movie/subtitles/Ultra.Pulpe.2018.B.Mandico.DVDRip.Cinetik.chs.srt"; 49 | 50 | private Context mContext; 51 | private VideoView mVideoView; 52 | private SimpleSubtitleView mSubtitleView; 53 | 54 | private Button mBtnPlayPause; 55 | private Button mBtnSettings; 56 | private Button mBtnForward; 57 | private Button mBtnRewind; 58 | private TextView mTvTips; 59 | private SettingsDialog mSettingsDialog; 60 | 61 | @Override 62 | protected void onCreate(Bundle savedInstanceState) { 63 | super.onCreate(savedInstanceState); 64 | setContentView(R.layout.activity_main); 65 | mContext = this; 66 | initViews(); 67 | setupEventListeners(); 68 | initPlayer(); 69 | } 70 | 71 | private void initViews() { 72 | mVideoView = findViewById(R.id.video_view); 73 | mSubtitleView = findViewById(R.id.subtitle_view); 74 | mTvTips = findViewById(R.id.tv_tips); 75 | mBtnPlayPause = findViewById(R.id.btn_play_pause); 76 | mBtnSettings = findViewById(R.id.btn_settings); 77 | mBtnForward = findViewById(R.id.btn_forward); 78 | mBtnRewind = findViewById(R.id.btn_rewind); 79 | mBtnPlayPause.requestFocus(); 80 | } 81 | 82 | private void setupEventListeners() { 83 | mBtnPlayPause.setOnClickListener(this); 84 | mBtnSettings.setOnClickListener(this); 85 | mBtnForward.setOnClickListener(this); 86 | mBtnRewind.setOnClickListener(this); 87 | 88 | } 89 | 90 | private void initPlayer() { 91 | mVideoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { 92 | @Override 93 | public void onPrepared(final MediaPlayer mp) { 94 | // 绑定MediaPlayer 95 | mSubtitleView.bindToMediaPlayer(mp); 96 | // 设置字幕 97 | mSubtitleView.setSubtitlePath(SUBTITLE_URL); 98 | } 99 | }); 100 | mVideoView.setVideoURI(Uri.parse(VIDEO_URL)); 101 | } 102 | 103 | private void play() { 104 | mVideoView.start(); 105 | mBtnPlayPause.setText("暂停"); 106 | mTvTips.setVisibility(View.GONE); 107 | } 108 | 109 | private void pause() { 110 | mVideoView.pause(); 111 | mBtnPlayPause.setText("播放"); 112 | } 113 | 114 | @Override 115 | protected void onDestroy() { 116 | mSubtitleView.destroy(); 117 | super.onDestroy(); 118 | } 119 | 120 | @Override 121 | public void onClick(final View v) { 122 | switch (v.getId()) { 123 | case R.id.btn_play_pause: 124 | if (mVideoView.isPlaying()) { 125 | pause(); 126 | } else { 127 | play(); 128 | } 129 | break; 130 | case R.id.btn_settings: 131 | showSettingsDialog(); 132 | break; 133 | case R.id.btn_forward: 134 | forward(); 135 | break; 136 | case R.id.btn_rewind: 137 | rewind(); 138 | break; 139 | } 140 | } 141 | 142 | 143 | private void forward() { 144 | int position = mVideoView.getCurrentPosition() + 60 * 1000; 145 | if (position > mVideoView.getDuration()) { 146 | position = mVideoView.getDuration(); 147 | Toast.makeText(mContext, "快进到头了", Toast.LENGTH_SHORT).show(); 148 | } 149 | mVideoView.seekTo(position); 150 | } 151 | 152 | private void rewind() { 153 | int position = mVideoView.getCurrentPosition() - 60 * 1000; 154 | if (position < 0) { 155 | position = 0; 156 | Toast.makeText(mContext, "快退到头了", Toast.LENGTH_SHORT).show(); 157 | } 158 | mVideoView.seekTo(position); 159 | } 160 | 161 | private void showSettingsDialog() { 162 | if (mSettingsDialog == null) { 163 | mSettingsDialog = new SettingsDialog(); 164 | mSettingsDialog.setOnSettingListener(new SettingsDialog.OnSettingListener() { 165 | @Override 166 | public void onSubtitleColorChange(final String color) { 167 | mSubtitleView.setTextColor(Color.parseColor(color)); 168 | } 169 | 170 | @Override 171 | public void onSubtitleFontSizeChange(final int fontSize) { 172 | mSubtitleView.setTextSize(fontSize); 173 | } 174 | 175 | @Override 176 | public void onSubtitlePositionChange(final Position position) { 177 | RelativeLayout.LayoutParams lp 178 | = (RelativeLayout.LayoutParams) mSubtitleView.getLayoutParams(); 179 | switch (position) { 180 | case TOP: 181 | mSubtitleView 182 | .setGravity(Gravity.CENTER_HORIZONTAL | Gravity.TOP); 183 | break; 184 | case CENTER: 185 | mSubtitleView 186 | .setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL); 187 | break; 188 | case BOTTOM: 189 | mSubtitleView 190 | .setGravity(Gravity.CENTER_HORIZONTAL | Gravity.BOTTOM); 191 | break; 192 | } 193 | mSubtitleView.setLayoutParams(lp); 194 | } 195 | }); 196 | } 197 | mSettingsDialog.show(getSupportFragmentManager(), "SettingsDialog"); 198 | } 199 | 200 | 201 | } 202 | -------------------------------------------------------------------------------- /example/src/main/java/com/avery/subtitle/example/SettingsDialog.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) of Avery 3 | * 4 | * _ooOoo_ 5 | * o8888888o 6 | * 88" . "88 7 | * (| -_- |) 8 | * O\ = /O 9 | * ____/`- -'\____ 10 | * .' \\| |// `. 11 | * / \\||| : |||// \ 12 | * / _||||| -:- |||||- \ 13 | * | | \\\ - /// | | 14 | * | \_| ''\- -/'' | | 15 | * \ .-\__ `-` ___/-. / 16 | * ___`. .' /- -.- -\ `. . __ 17 | * ."" '< `.___\_<|>_/___.' >'"". 18 | * | | : `- \`.;`\ _ /`;.`/ - ` : | | 19 | * \ \ `-. \_ __\ /__ _/ .-` / / 20 | * ======`-.____`-.___\_____/___.-`____.-'====== 21 | * `=- -=' 22 | * ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 23 | * Buddha bless, there will never be bug!!! 24 | */ 25 | 26 | package com.avery.subtitle.example; 27 | 28 | import android.os.Bundle; 29 | import android.support.annotation.NonNull; 30 | import android.support.annotation.Nullable; 31 | import android.support.v4.app.DialogFragment; 32 | import android.view.LayoutInflater; 33 | import android.view.View; 34 | import android.view.ViewGroup; 35 | import android.widget.Button; 36 | 37 | /** 38 | * @author AveryZhong. 39 | */ 40 | 41 | public class SettingsDialog extends DialogFragment implements View.OnClickListener { 42 | 43 | @Override 44 | public void onCreate(@Nullable final Bundle savedInstanceState) { 45 | super.onCreate(savedInstanceState); 46 | setStyle(STYLE_NO_FRAME, android.R.style.Theme_Translucent_NoTitleBar_Fullscreen); 47 | } 48 | 49 | @Nullable 50 | @Override 51 | public View onCreateView(@NonNull final LayoutInflater inflater, 52 | @Nullable final ViewGroup container, 53 | @Nullable final Bundle savedInstanceState) { 54 | return inflater.inflate(R.layout.dialog_settings, container, false); 55 | } 56 | 57 | @Override 58 | public void onViewCreated(@NonNull final View view, @Nullable final Bundle savedInstanceState) { 59 | super.onViewCreated(view, savedInstanceState); 60 | final Button btnColorWhite = view.findViewById(R.id.btn_white); 61 | final Button btnColorRed = view.findViewById(R.id.btn_red); 62 | final Button btnColorPurple = view.findViewById(R.id.btn_purple); 63 | 64 | final Button btnFontSizeSmall = view.findViewById(R.id.btn_small); 65 | final Button btnFontSizeMiddle = view.findViewById(R.id.btn_middle); 66 | final Button btnFontSizeBig = view.findViewById(R.id.btn_big); 67 | 68 | final Button btnPositionTop = view.findViewById(R.id.btn_top); 69 | final Button btnPositionCenter = view.findViewById(R.id.btn_center); 70 | final Button btnPositionBottom = view.findViewById(R.id.btn_bottom); 71 | 72 | 73 | btnColorWhite.setOnClickListener(this); 74 | btnColorRed.setOnClickListener(this); 75 | btnColorPurple.setOnClickListener(this); 76 | 77 | btnFontSizeSmall.setOnClickListener(this); 78 | btnFontSizeMiddle.setOnClickListener(this); 79 | btnFontSizeBig.setOnClickListener(this); 80 | 81 | btnPositionTop.setOnClickListener(this); 82 | btnPositionCenter.setOnClickListener(this); 83 | btnPositionBottom.setOnClickListener(this); 84 | 85 | } 86 | 87 | @Override 88 | public void onClick(final View v) { 89 | if (mOnSettingListener == null) { 90 | return; 91 | } 92 | switch (v.getId()) { 93 | case R.id.btn_white: 94 | mOnSettingListener.onSubtitleColorChange("#ffffff"); 95 | break; 96 | case R.id.btn_red: 97 | mOnSettingListener.onSubtitleColorChange("#ff0000"); 98 | break; 99 | case R.id.btn_purple: 100 | mOnSettingListener.onSubtitleColorChange("#7F0E92"); 101 | break; 102 | 103 | case R.id.btn_small: 104 | mOnSettingListener.onSubtitleFontSizeChange(12); 105 | break; 106 | case R.id.btn_middle: 107 | mOnSettingListener.onSubtitleFontSizeChange(16); 108 | break; 109 | case R.id.btn_big: 110 | mOnSettingListener.onSubtitleFontSizeChange(22); 111 | break; 112 | 113 | case R.id.btn_top: 114 | mOnSettingListener 115 | .onSubtitlePositionChange(OnSettingListener.Position.TOP); 116 | break; 117 | case R.id.btn_center: 118 | mOnSettingListener 119 | .onSubtitlePositionChange(OnSettingListener.Position.CENTER); 120 | break; 121 | case R.id.btn_bottom: 122 | mOnSettingListener 123 | .onSubtitlePositionChange(OnSettingListener.Position.BOTTOM); 124 | break; 125 | } 126 | } 127 | 128 | private OnSettingListener mOnSettingListener; 129 | 130 | public void setOnSettingListener(final OnSettingListener onSettingListener) { 131 | mOnSettingListener = onSettingListener; 132 | } 133 | 134 | public interface OnSettingListener { 135 | void onSubtitleColorChange(String color); 136 | 137 | void onSubtitleFontSizeChange(int fontSize); 138 | 139 | void onSubtitlePositionChange(Position position); 140 | 141 | enum Position { 142 | TOP, CENTER, BOTTOM 143 | } 144 | } 145 | } 146 | -------------------------------------------------------------------------------- /example/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 12 | 13 | 19 | 22 | 25 | 26 | 27 | 28 | 34 | 35 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/bg_button.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/bg_button2.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/bg_button_color_purple.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/bg_button_color_red.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/bg_button_color_white.xml: -------------------------------------------------------------------------------- 1 | 2 | 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 | -------------------------------------------------------------------------------- /example/src/main/res/drawable/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 33 | 36 | 41 | 46 | 51 | 56 | 61 | 66 | 71 | 76 | 81 | 86 | 91 | 96 | 101 | 106 | 111 | 116 | 121 | 126 | 131 | 136 | 141 | 146 | 151 | 156 | 161 | 166 | 171 | 176 | 181 | 186 | 191 | 196 | 197 | -------------------------------------------------------------------------------- /example/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 26 | 27 | 34 | 35 | 41 | 42 | 52 | 53 | 62 | 63 | 70 | 71 |