├── .gitignore
├── README.md
├── RNIndicator.podspec
├── android
├── build.gradle
└── src
│ └── main
│ ├── AndroidManifest.xml
│ └── java
│ └── com
│ └── ngxu
│ └── videoplayer
│ ├── AppBrightness.java
│ ├── HeidBottomBtn.java
│ ├── HideBottomNa.java
│ ├── RNVideoplayerModule.java
│ ├── RNVideoplayerPackage.java
│ └── SetAppBrightness.java
├── component
└── svg.js
├── index.js
├── ios
├── RNIndicator.h
├── RNIndicator.m
└── RNIndicator.xcodeproj
│ └── project.pbxproj
├── package.json
├── utils
├── formatSeconds.js
└── getMaxdata.js
└── view
└── index.js
/.gitignore:
--------------------------------------------------------------------------------
1 | example
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # 已废弃不会更新,不推荐使用(由于没有mac设备等问题)
2 |
3 | # 已废弃不会更新,不推荐使用(由于没有mac设备等问题)
4 |
5 | # 已废弃不会更新,不推荐使用(由于没有mac设备等问题)
6 |
7 | # 已废弃不会更新,不推荐使用(由于没有mac设备等问题)
8 |
9 |
10 |
11 | # react-native-rn-videoplayer
12 |
13 |
14 |
15 |
16 | - 视频上下滑动调节音量、屏幕亮度、长按左右两边快进退、左右滑动以及拖动进度条调节视频进度,视频控件锁定,全屏切换,缓冲进度,双击视频暂停,等功能,基于react-native-video
17 | - ps:Android改变亮度无需获取高级权限,只改变当前active也就是当前页面的亮度,改变亮度后,返回进入到其他页面会恢复到原来的亮度。
18 |
19 | - 如果你的视频全屏后尺寸没发生改变,参考[全屏尺寸问题18](https://github.com/A-ANing/react-native-rn-videoplayer/issues/18)
20 |
21 | - Version 2.x requires react-native >= 0.60.0
22 | - Version 1.3.2 requires react-native <= 0.59.9
23 |
24 |
25 |
26 |
27 |
28 | ## gif预览 [ios](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/43621fcd-e016-4f94-967e-47000082529c.gif) 和 [android](https://vkceyugu.cdn.bspapp.com/VKCEYUGU-imgbed/683885c8-fcfd-4434-88b3-f52e90ccfc7f.gif) 不是最新版
29 |
30 |
31 |
32 |
33 | # 增加功能
34 |
35 | - v2.2.10 支持左右两边长按快进退,返回按钮右边显示视频名字、自定义缓冲提示图标和文字、暂停文字、快进退的文字!
36 |
37 |
38 |
39 |
40 |
41 | - v2.2.9 showSmallCont={false}小屏是否显示返回按钮,默认为true; 自定义进度条颜色(见api)
42 |
43 | - v2.2.8 当ios设备为iPhone X以上,全屏时隐藏底部小横条
44 |
45 | - v2.2.5 autoPlay={false}是否自动播放,默认为true
46 |
47 | - v2.2.1 增加手势左右滑动视频区域(非进度条上的点)来调整视频进度
48 |
49 | - v2.0.8 自定义小屏状态栏 类型fun
50 | 默认状态栏为沉浸式,黑底白字,有状态栏高度,可查看view/index.js 的Header组件
51 | ```
52 | null}//不使用默认状态栏 跟当前app保持一致
54 | statusBar={()=>}//自定义
55 | />
56 | ```
57 |
58 | - v2.0.6 增加锁定视频控件,锁定用户操作(调节音量/亮度,展示隐藏控件)
59 |
60 | `
61 | lockControl (true/false 默认关闭)
62 | `
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 |
75 |
76 |
77 |
78 |
79 |
80 | ## Getting started
81 | 1.
82 | ```shell
83 | npm install react-native-rn-videoplayer --save
84 | ```
85 |
86 | 2.
87 | ## - - android
88 |
89 | Open up `android/app/src/main/java/[...]/MainActivity.java`
90 |
91 | ```diff
92 | +import android.content.Intent;
93 | +import android.content.res.Configuration;
94 | public class MainActivity extends ReactActivity {
95 |
96 | ...
97 |
98 | + @Override
99 | + public void onConfigurationChanged(Configuration newConfig) {
100 | + super.onConfigurationChanged(newConfig);
101 | + Intent intent = new Intent("onConfigurationChanged");
102 | + intent.putExtra("newConfig", newConfig);
103 | + this.sendBroadcast(intent);
104 | + }
105 | ...
106 | }
107 | ```
108 |
109 | ## - - iOS
110 |
111 | Add the following to your project's `AppDelegate.m`:
112 |
113 | ```diff
114 | +#import "Orientation.h"
115 | +#import
116 |
117 | @implementation AppDelegate
118 |
119 | // ...
120 |
121 | +- (UIInterfaceOrientationMask)application:(UIApplication *)application supportedInterfaceOrientationsForWindow:(UIWindow *)window {
122 | + return [Orientation getOrientation];
123 | +}
124 |
125 | //找到这行
126 | UIViewController *rootViewController = [UIViewController new];
127 |
128 | //改为
129 | UIViewController *rootViewController = [HomeIndicatorView new];
130 |
131 |
132 | @end
133 | ```
134 |
135 | ## RN >= 0.60
136 |
137 | ### ios
138 | ```
139 | cd ios
140 |
141 | pod install
142 | ```
143 |
144 | ### Android.
145 | #### Most of them are automatically linked. If you can’t find XX, you should link manually
146 | - settings.gradle
147 | ```diff
148 | rootProject.name = 'TestPack622'
149 | apply from: file("../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesSettingsGradle(settings)
150 |
151 | + include ':react-native-linear-gradient'
152 | + project(':react-native-linear-gradient').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-linear-gradient/android')
153 | + include ':react-native-svg'
154 | + project(':react-native-svg').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-svg/android')
155 | + include ':react-native-orientation-locker'
156 | + project(':react-native-orientation-locker').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-orientation-locker/android')
157 | + include ':react-native-video'
158 | + project(':react-native-video').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-video/android-exoplayer')
159 | + include ':react-native-system-setting'
160 | + project(':react-native-system-setting').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-system-setting/android')
161 |
162 | include ':app'
163 | ```
164 |
165 | - MainApplication.java
166 |
167 | ```diff
168 |
169 | + import com.horcrux.svg.SvgPackage;
170 | + import com.BV.LinearGradient.LinearGradientPackage; // <--- This!
171 | + import org.wonday.orientation.OrientationPackage;
172 | + import com.ninty.system.setting.SystemSettingPackage;
173 | + import com.brentvatne.react.ReactVideoPackage;
174 |
175 |
176 | ···
177 | @Override
178 | protected List getPackages() {
179 | @SuppressWarnings("UnnecessaryLocalVariable")
180 | List packages = new PackageList(this).getPackages();
181 | // Packages that cannot be autolinked yet can be added manually here, for example:
182 | + packages.add(new LinearGradientPackage());
183 | + packages.add(new SvgPackage());
184 | + packages.add(new OrientationPackage());
185 | + packages.add(new SystemSettingPackage());
186 | + packages.add(new ReactVideoPackage());
187 | return packages;
188 | }
189 | ···
190 |
191 | ```
192 |
193 | - app/build.gradle
194 |
195 | ```diff
196 | dependencies {
197 | + implementation project(':react-native-svg')
198 | + implementation project(':react-native-linear-gradient')
199 | + implementation project(':react-native-orientation-locker')
200 | + implementation project(':react-native-system-setting')
201 | + implementation project(':react-native-video')
202 | }
203 |
204 | ```
205 |
206 |
207 | ## RN <= 0.59
208 |
209 |
210 | ```shell
211 | react-native link react-native-linear-gradient
212 | react-native link react-native-orientation-locker
213 | react-native link react-native-svg
214 | react-native link react-native-system-setting
215 | react-native link react-native-video
216 | ```
217 |
218 | #### Android
219 |
220 |
221 |
222 | 1. Append the following lines to `android/settings.gradle`:
223 | ``` javascript
224 | include ':react-native-rn-videoplayer'
225 | project(':react-native-rn-videoplayer').projectDir = new File(rootProject.projectDir, '../node_modules/react-native-rn-videoplayer/android')
226 | ```
227 | 2. Insert the following lines inside the dependencies block in `android/app/build.gradle`:
228 | ```
229 | compile project(':react-native-rn-videoplayer')
230 | ```
231 |
232 | 3. Open up `android/app/src/main/java/[...]/MainApplication.java`
233 |
234 | - Add
235 | ```java
236 | import com.ngxu.videoplayer.RNVideoplayerPackage;
237 |
238 | new RNVideoplayerPackage() //to the list returned by the `getPackages()` method
239 | ```
240 |
241 |
242 |
243 |
244 | ## Usage
245 | ```javascript
246 | import VideoPlayer from 'react-native-rn-videoplayer';
247 |
248 | this.player=ref}
253 | lockControl={true}//控件锁定功能 v2.0.6增加
254 | moreSetting={() => null}//右上角更多按钮 输出null则不显示
255 | onSmallBack={()=>{this.props.navigation.goBack()}}
256 | />
257 |
258 | ```
259 | # api
260 | - url 视频地址
261 | - showSmallCont={bool} 小屏是否隐藏返回按钮 默认false;
262 | - changeWindows() 切换全屏或者小屏
263 |
264 | changeWindows(boolean) true 全屏, false 小屏
265 |
266 | Example:
267 | ```javascript
268 | this.player=ref}/>
269 | this.player.changeWindows(true); // 全屏
270 | ```
271 |
272 | - storeComponent 右上角收藏按钮的图标
273 | ```javascript
274 | storeComponent={()=>}
275 | ```
276 | - moreSetting 右上角更多按钮的图标
277 | ```javascript
278 | moreSetting={()=>}
279 | ```
280 |
281 | - speedColor 当前播放进度条颜色 "#e54602"
282 |
283 | - dotColor 进度条上的圆点颜色 "#e54602"
284 |
285 | - dotBorderColor 进度条上的圆点被按下时的边框颜色 "rgba(255,255,255,0.3)"
286 |
287 | - bottomSpeedColor 最底部播放进度的颜色 "#e54602"
288 |
289 | - cachColor 缓冲进度条颜色 "#ffffff"
290 |
291 | - allSpeedColor 整个进度条颜色 "rgba(0,0,0,0.4)
292 |
293 | - backVideoName 返回按钮旁的文字 string
294 |
295 | - pausedTipText 已暂停的文字 string
296 |
297 | - loadingText 正在缓冲的文字 string
298 |
299 | - loadingIcon 加载的图标 loadingIcon={<>>}
300 |
301 | - solText 快退中的文字 string
302 |
303 | - fastText 快进中的文字 string
304 |
305 |
306 | - setPaused 播放暂停
307 | ```javascript
308 | this.player.setPaused(true)//true暂停;false播放;
309 |
310 | this.player=ref}
312 | >
313 |
314 | ```
315 | - reLoad 重新加载
316 | ```javascript
317 | this.player.reLoad()
318 |
319 | this.player=ref}
321 | >
322 |
323 | ```
324 |
325 | - rePlay 重置进度为0
326 | ```javascript
327 |
328 | this.player.reLoad(false)
329 | //false 不自动播放
330 | //默认为true 自动播放
331 | ```
332 |
333 | - onSmallBack 当视频是小窗口时 点击返回按钮的回调 可以在此添加返回上个页面的功能 func
334 | - onStore 点击右上角收藏按钮的回调 func
335 | - onMoreFun 点击右上角更多按钮的回调 func
336 | - onWindowChange 窗口改变的回调 func
337 | ```javascript
338 |
339 | {}}//e:"full"全屏 "small"小屏
341 | >
342 |
343 | ```
344 |
345 | - continuous 是否开启全屏时的选集功能 适合连续剧 默认 false
346 | ```js
347 | continuous={true}
348 | ```
349 |
350 | - renderAllSeenList 点击选集后显示的集数列表
351 | ```js
352 | ···
353 | this.player=ref}
356 | renderAllSeenList={this.renderAllSeenList}
357 | />
358 |
359 | ···
360 | renderAllSeenList = () => (
361 |
362 |
363 |
373 |
374 |
375 | )
376 |
377 | ```
378 |
379 | - nextBtnFun 全屏时下一集按钮的方法 当是最后一集的时候应将值变为false,将按钮置灰
380 | ```js
381 | const {data} = this.state
382 | //data.index为集数
383 | //当当前播放的集数和总集数相同时,将nextBtnFun重置为false
384 | nextBtnFun={
385 | data.index == data.datalist[data.datalist.length - 1].num - 1 ? false : this.nextBtnFun
386 | }
387 | ```
388 |
389 | - onLoad 视频加载成功可以开始播放的回调 继承react-native-veideo
390 | - onSeek 调整进度后的回调 继承react-native-video的onSeek
391 | - onEnd 播放完的回调 继承react-native-video的onSeek
392 | - onBuffer 是否处于等待加载时 这里可以取到视频卡住展示loading或者是视频可以播放隐藏loading的回调 继承react-native-video的onBuffer
393 | - poster 视频封面图 视频还不能播放的时候展示的封面图 并不是loading框 继承react-native-video的poster eg:poster={"http://xudaxianer.cn/artcover/2020-12-11/1607675992959.jpg"}
394 |
395 | - ..... 继承全部的react-native-video的方法及属性
396 |
397 |
398 |
399 |
400 |
401 | # 暴露方法
402 | `import {NgxuSetting} from 'react-native-rn-videoplayer'`
403 |
404 | ## 显示或者隐藏安卓底部虚拟按键
405 | ```javascript
406 | const Setting = new NgxuSetting()
407 | Setting.hideAndroidBottom()
408 | Setting.showAndroidBottom()
409 | ```
410 |
411 | ## 获取手机系统亮度
412 | ```javascript
413 | const Setting = new NgxuSetting()
414 | Setting.getBrightness((e)=>{consoloe.log(e)})
415 | ```
416 |
417 |
418 |
419 | ## 改变ios系统亮度 android 当前app亮度
420 | - android仅仅只改变当前active亮度,不会修改系统亮度,修改系统亮度是非常麻烦的事情,需要用户手动打开手机设置,app权限设置,手动打开“允许修改系统设置“的高级权限
421 | - ios则是改变系统亮度你可以
422 | ```javascript
423 | const Setting = new NgxuSetting()
424 | Setting.SetBrightness(1)//0-1之间
425 | ```
426 |
--------------------------------------------------------------------------------
/RNIndicator.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "RNIndicator"
4 | s.version = "1.0.0"
5 | s.summary = "RNIndicator"
6 | s.description = <<-DESC
7 | RNIndicator
8 | DESC
9 | s.homepage = "https://github.com/A-ANing/react-native-rn-videoplayer"
10 | s.license = "MIT"
11 | # s.license = { :type => "MIT", :file => "FILE_LICENSE" }
12 | s.author = { "author" => "author@domain.cn" }
13 | s.platform = :ios, "7.0"
14 | s.source = { :git => "https://github.com/A-ANing/react-native-rn-videoplayer.git", :tag => "master" }
15 | s.source_files = "ios/**/*.{h,m}"
16 | s.requires_arc = true
17 |
18 |
19 | s.dependency "React"
20 | #s.dependency "others"
21 |
22 | end
23 |
24 |
--------------------------------------------------------------------------------
/android/build.gradle:
--------------------------------------------------------------------------------
1 |
2 | buildscript {
3 | repositories {
4 | jcenter()
5 | maven {
6 | url 'https://maven.google.com/'
7 | name 'Google'
8 | }
9 | google()
10 | }
11 |
12 | dependencies {
13 | classpath 'com.android.tools.build:gradle:3.3.1'
14 | }
15 | }
16 |
17 | apply plugin: 'com.android.library'
18 |
19 | android {
20 | compileSdkVersion 28
21 | buildToolsVersion "28.0.3"
22 |
23 | defaultConfig {
24 | minSdkVersion 16
25 | targetSdkVersion 28
26 | versionCode 1
27 | versionName "1.0"
28 | }
29 | lintOptions {
30 | abortOnError false
31 | }
32 | }
33 |
34 | repositories {
35 | mavenCentral()
36 | google()
37 | }
38 |
39 | dependencies {
40 | compile 'com.facebook.react:react-native:+'
41 | }
42 |
--------------------------------------------------------------------------------
/android/src/main/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/AppBrightness.java:
--------------------------------------------------------------------------------
1 | package com.ngxu.videoplayer;
2 |
3 | import android.widget.Toast;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.bridge.ReactContext;
9 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
10 | import com.facebook.react.bridge.ReactMethod;
11 | import android.os.Build;
12 | import java.util.Map;
13 | import java.util.HashMap;
14 | import android.view.View;
15 | import java.lang.ref.WeakReference;
16 |
17 | public class AppBrightness extends ReactContextBaseJavaModule {
18 |
19 | private static final String DURATION_SHORT_KEY = "SHORT";
20 | private static final String DURATION_LONG_KEY = "LONG";
21 | private static WeakReference activity;
22 | public AppBrightness(ReactApplicationContext reactContext) {
23 | super(reactContext);
24 | }
25 |
26 | @Override
27 | public String getName() {
28 | return "AppBrightness";
29 | }
30 |
31 | @Override
32 | public Map getConstants() {
33 | final Map constants = new HashMap<>();
34 | constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
35 | constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
36 | return constants;
37 | }
38 |
39 |
40 |
41 | @ReactMethod
42 |
43 | public void setAppBrightness(float brightnessPercent) {
44 | SetAppBrightness.goSetAppBrightness(getCurrentActivity(),brightnessPercent);
45 | }
46 |
47 |
48 |
49 |
50 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/HeidBottomBtn.java:
--------------------------------------------------------------------------------
1 | package com.ngxu.videoplayer;
2 | import android.os.Build;
3 | import android.view.View;
4 | import android.app.Activity;
5 | import java.lang.ref.WeakReference;
6 | import android.view.View;
7 | import android.graphics.Color;
8 | import android.view.WindowManager;
9 | import android.view.Window;
10 | public class HeidBottomBtn {
11 |
12 | private static WeakReference mActivity;
13 | public static void goHide( Activity activity,String message) {
14 |
15 |
16 |
17 | mActivity=new WeakReference(activity);
18 |
19 | if (activity == null) {
20 | if (mActivity == null) {
21 | return;
22 | }
23 | activity = mActivity.get();
24 | }
25 |
26 | if (activity == null) return;
27 |
28 | final Activity _activity = activity;
29 |
30 | _activity.runOnUiThread(new Runnable() {
31 | @Override
32 | public void run() {
33 | //隐藏虚拟按键
34 |
35 |
36 | if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) { // lower api
37 | View v = _activity.getWindow().getDecorView();
38 | v.setSystemUiVisibility(View.GONE);
39 | } else if (Build.VERSION.SDK_INT >= 19) {
40 | //for new api versions.
41 | View decorView = _activity.getWindow().getDecorView();
42 |
43 | int uiOptions = View.SYSTEM_UI_FLAG_HIDE_NAVIGATION //隐藏系统NavigationBar。
44 | | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
45 | |View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
46 | | View.SYSTEM_UI_FLAG_LAYOUT_STABLE
47 | | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY|View.SYSTEM_UI_FLAG_IMMERSIVE
48 | |View.SYSTEM_UI_FLAG_FULLSCREEN;//隐藏StatusBar。(>=api16)
49 |
50 | decorView.setSystemUiVisibility(uiOptions);
51 | //设置页面全屏显示
52 | if (Build.VERSION.SDK_INT >= 28) {
53 | WindowManager.LayoutParams lp = _activity.getWindow().getAttributes();
54 | lp.layoutInDisplayCutoutMode = WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_SHORT_EDGES;
55 | //设置页面延伸到刘海区显示
56 | _activity.getWindow().setAttributes(lp);
57 | }
58 | }
59 |
60 | }
61 | });
62 |
63 | // Toast.makeText(getReactApplicationContext(), message, duration).show();
64 |
65 | }
66 |
67 |
68 |
69 | public static void goShow( Activity activity,String message) {
70 |
71 |
72 |
73 | mActivity=new WeakReference(activity);
74 |
75 | if (activity == null) {
76 | if (mActivity == null) {
77 | return;
78 | }
79 | activity = mActivity.get();
80 | }
81 |
82 | if (activity == null) return;
83 |
84 | final Activity _activity = activity;
85 |
86 | _activity.runOnUiThread(new Runnable() {
87 | @Override
88 | public void run() {
89 |
90 |
91 |
92 | //显示虚拟按键
93 | if (Build.VERSION.SDK_INT > 11 && Build.VERSION.SDK_INT < 19) {
94 | //低版本sdk
95 | View v = _activity.getWindow().getDecorView();
96 | v.setSystemUiVisibility(View.VISIBLE);
97 | } else if (Build.VERSION.SDK_INT >= 19) {
98 | View decorView = _activity.getWindow().getDecorView();
99 | int uiOptions = View.SYSTEM_UI_FLAG_FULLSCREEN;
100 | decorView.setSystemUiVisibility(uiOptions);
101 | }
102 |
103 |
104 | }
105 | });
106 |
107 | // Toast.makeText(getReactApplicationContext(), message, duration).show();
108 |
109 | }
110 |
111 |
112 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/HideBottomNa.java:
--------------------------------------------------------------------------------
1 | package com.ngxu.videoplayer;
2 |
3 | import android.widget.Toast;
4 | import android.app.Activity;
5 | import android.content.Context;
6 | import com.facebook.react.bridge.NativeModule;
7 | import com.facebook.react.bridge.ReactApplicationContext;
8 | import com.facebook.react.bridge.ReactContext;
9 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
10 | import com.facebook.react.bridge.ReactMethod;
11 | import android.os.Build;
12 | import java.util.Map;
13 | import java.util.HashMap;
14 | import android.view.View;
15 | import java.lang.ref.WeakReference;
16 |
17 | public class HideBottomNa extends ReactContextBaseJavaModule {
18 |
19 | private static final String DURATION_SHORT_KEY = "SHORT";
20 | private static final String DURATION_LONG_KEY = "LONG";
21 | private static WeakReference activity;
22 | public HideBottomNa(ReactApplicationContext reactContext) {
23 | super(reactContext);
24 | }
25 |
26 | @Override
27 | public String getName() {
28 | return "HideBottomNa";
29 | }
30 |
31 | @Override
32 | public Map getConstants() {
33 | final Map constants = new HashMap<>();
34 | constants.put(DURATION_SHORT_KEY, Toast.LENGTH_SHORT);
35 | constants.put(DURATION_LONG_KEY, Toast.LENGTH_LONG);
36 | return constants;
37 | }
38 |
39 |
40 | /**
41 | * 要导出一个方法给JavaScript使用,Java方法需要使用注解@ReactMethod。方法的返回类型必须为void。
42 | * @param message
43 | * @param duration
44 | */
45 | @ReactMethod
46 |
47 | public void hide() {
48 | HeidBottomBtn.goHide(getCurrentActivity(),"123");
49 | }
50 |
51 | @ReactMethod
52 |
53 | public void show() {
54 | HeidBottomBtn.goShow(getCurrentActivity(),"123");
55 | }
56 |
57 |
58 |
59 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/RNVideoplayerModule.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ngxu.videoplayer;
3 |
4 | import com.facebook.react.bridge.ReactApplicationContext;
5 | import com.facebook.react.bridge.ReactContextBaseJavaModule;
6 | import com.facebook.react.bridge.ReactMethod;
7 | import com.facebook.react.bridge.Callback;
8 |
9 | public class RNVideoplayerModule extends ReactContextBaseJavaModule {
10 |
11 | private final ReactApplicationContext reactContext;
12 |
13 | public RNVideoplayerModule(ReactApplicationContext reactContext) {
14 | super(reactContext);
15 | this.reactContext = reactContext;
16 | }
17 |
18 | @Override
19 | public String getName() {
20 | return "RNVideoplayer";
21 | }
22 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/RNVideoplayerPackage.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ngxu.videoplayer;
3 |
4 | import java.util.Arrays;
5 | import java.util.Collections;
6 | import java.util.List;
7 |
8 | import com.facebook.react.ReactPackage;
9 | import com.facebook.react.bridge.NativeModule;
10 | import com.facebook.react.bridge.ReactApplicationContext;
11 | import com.facebook.react.uimanager.ViewManager;
12 | import com.facebook.react.bridge.JavaScriptModule;
13 | import java.util.ArrayList;
14 | public class RNVideoplayerPackage implements ReactPackage {
15 |
16 | @Override
17 | public List createNativeModules(ReactApplicationContext reactContext) {
18 | List modules = new ArrayList<>();
19 |
20 | modules.add(
21 | new AppBrightness(reactContext)
22 | );
23 | modules.add(
24 | new HideBottomNa(reactContext)
25 | );
26 | return modules;
27 | }
28 |
29 |
30 | // Deprecated from RN 0.47
31 | public List> createJSModules() {
32 | return Collections.emptyList();
33 | }
34 |
35 | @Override
36 | public List createViewManagers(ReactApplicationContext reactContext) {
37 | return Collections.emptyList();
38 | }
39 | }
--------------------------------------------------------------------------------
/android/src/main/java/com/ngxu/videoplayer/SetAppBrightness.java:
--------------------------------------------------------------------------------
1 |
2 | package com.ngxu.videoplayer;
3 | import android.os.Build;
4 |
5 | import android.app.Activity;
6 | import java.lang.ref.WeakReference;
7 | import android.view.View;
8 |
9 | import android.view.WindowManager;
10 | import android.view.Window;
11 |
12 | public class SetAppBrightness {
13 |
14 | private static WeakReference mActivity;
15 | public static void goSetAppBrightness(Activity activity, final float brightnessPercent)
16 | {
17 |
18 | mActivity=new WeakReference(activity);
19 |
20 | if (activity == null) {
21 | if (mActivity == null) {
22 | return;
23 | }
24 | activity = mActivity.get();
25 | }
26 |
27 | if (activity == null) return;
28 |
29 | final Activity _activity = activity;
30 |
31 | _activity.runOnUiThread(new Runnable() {
32 | @Override
33 | public void run() {
34 | Window window = _activity.getWindow();
35 | WindowManager.LayoutParams layoutParams = window.getAttributes();
36 | layoutParams.screenBrightness = brightnessPercent;
37 | window.setAttributes(layoutParams);
38 | }
39 | });
40 | }
41 |
42 | }
43 |
44 |
45 |
46 |
--------------------------------------------------------------------------------
/component/svg.js:
--------------------------------------------------------------------------------
1 | import React from 'react'
2 | import Svg, { Path } from 'react-native-svg'
3 |
4 |
5 |
6 |
7 | //视频播放 收藏按钮
8 |
9 | export const SvgVideoScang= props => (
10 |
11 |
12 | )
13 |
14 |
15 |
16 |
17 | //视频播放 已收藏按钮
18 |
19 | export const SvgVideoScanged= props => (
20 |
21 |
22 | )
23 |
24 |
25 |
26 | //视频播放 右上角更多
27 |
28 | export const SvgVideoSetting= props => (
29 |
30 |
31 |
32 | )
33 |
34 |
35 | //视频播放 暂停
36 |
37 | export const SvgVideoStop= props => (
38 |
39 |
40 |
41 | )
42 |
43 |
44 | //视频播放 播放
45 |
46 | export const SvgVideoPlay= props => (
47 |
48 |
49 | )
50 |
51 |
52 | //视频播放 全屏
53 |
54 | export const SvgVideoAllBox= props => (
55 |
56 |
57 | )
58 |
59 |
60 | //视频播放 小屏
61 |
62 | export const SvgVideoSmallBox= props => (
63 |
64 |
65 |
66 |
67 | )
68 |
69 | //视频播放 小屏
70 |
71 | export const SvgVideoDotJd= props => (
72 |
73 |
74 |
75 |
76 | )
77 |
78 |
79 | //视频播放 快进
80 |
81 | export const SvgVideoFastSpeed= props => (
82 |
83 |
84 |
85 |
86 |
87 | )
88 | //视频播放 返回
89 |
90 | export const SvgVideoBack= props => (
91 |
92 |
93 |
94 |
95 |
96 |
97 | )
98 |
99 | //视频播放 音量调节(有声音)
100 |
101 |
102 | export const SvgVideoSound= props => (
103 |
104 |
105 |
106 |
107 | )
108 |
109 |
110 |
111 | //视频播放 音量调节(静音)
112 | export const SvgVideoNoSound= props => (
113 |
114 |
115 |
116 | )
117 |
118 |
119 | //视频亮度调节
120 | export const SvgVideoBrightness= props => (
121 |
122 |
123 |
124 |
125 |
126 | )
127 |
128 |
129 | export const SvgVideoLoading= props => (
130 |
131 |
132 |
133 | )
134 |
135 |
136 | export const SvgVideoNextBtn = props =>(
137 |
138 |
139 |
140 |
141 | )
142 |
143 |
144 | export const SvgVideoUnlock = props =>(
145 |
146 |
147 |
148 | )
149 |
150 |
151 |
152 | export const SvgVideoLocking = props =>(
153 |
154 |
155 |
156 | )
157 |
158 |
--------------------------------------------------------------------------------
/index.js:
--------------------------------------------------------------------------------
1 | //修复播放不同分辨率视频,不会重新测量分辨率的问题https://github.com/react-native-community/react-native-video/pull/2053
2 | import React from 'react';
3 | import {
4 | Text,
5 | StyleSheet,
6 | View,
7 | TouchableOpacity,
8 | Dimensions,
9 | StatusBar,
10 | Animated,
11 | NativeModules,
12 | Alert,
13 | Easing,
14 | PanResponder,
15 | Platform
16 | } from 'react-native';
17 | import {
18 | Loading,
19 | TipsPaused,
20 | Brightness,
21 | Volume,
22 | BottomSpeed,
23 | Speed,
24 | Header,
25 | SpeedTipTime,
26 | Lock,
27 | AnFastSvg
28 | } from './view/index';
29 | import {
30 | SvgVideoNextBtn,
31 | SvgVideoSetting,
32 | SvgVideoStop,
33 | SvgVideoPlay,
34 | SvgVideoAllBox,
35 | SvgVideoSmallBox,
36 | SvgVideoBack,
37 | SvgVideoScang,
38 | SvgVideoFastSpeed
39 | } from './component/svg';
40 | import SystemSetting from 'react-native-system-setting';
41 | import LinearGradient from 'react-native-linear-gradient';
42 | import Video from 'react-native-video';
43 | import { formatSeconds } from './utils/formatSeconds';
44 | import Orientation from 'react-native-orientation-locker';
45 | import { getMaxdata } from './utils/getMaxdata';
46 |
47 | const { height, width } = Dimensions.get('screen');
48 |
49 |
50 | class VideoPlayer extends React.Component {
51 | static defaultProps = {
52 | autoPlay: true,
53 | resizeMode:"contain",
54 | posterResizeMode:"cover",
55 | showSmallCont: true,
56 | speedColor: "#e54602",
57 | dotColor: "#e54602",
58 | dotBorderColor: "rgba(255,255,255,0.3)",
59 | bottomSpeedColor: "#e54602",
60 | cachColor: "#ffffff",
61 | allSpeedColor: "rgba(0,0,0,0.4)"
62 | }
63 | constructor(props) {
64 | super(props)
65 | this.noVipSecond = this.props.noVipSecond || 5//没有vip可观看的分钟数
66 | this.url = this.props.url
67 | this.spinValue = new Animated.Value(0)
68 | this.adminBrightness = ''
69 | this.soundData = 0//音量
70 | this.soundDataY = 0
71 | this.speedData = 0//滑动进度
72 | this.speedDataX = 0
73 | this.BrightnessData = 0//亮度
74 | this.BrightnessY = 0
75 | this.nowTime = "00:00"
76 | this.nowCurrentTime = 0//当前播放秒数
77 | this.defSpeed = 1
78 | this.speedTouchScale = 5//长按快进快退的宽度 跟屏幕宽度的比例
79 | this.speedFastValue = 3 //长按视频右边的快进速率
80 | this.speedSlowValue = 3
81 | this.dotX = new Animated.Value(0),
82 | this.bufferX = new Animated.Value(0),
83 | this.soundAnima = new Animated.Value(0),//音量
84 | this.playDotX = null,//控件没被隐藏时的进度动画
85 | this.playhideContsDotX = null,//控件被隐藏时,最下面的进度动画
86 | this.playBufferX = null,
87 | this.recordHandeY = [],//记录滑动y值
88 | this.recordHandeX = [],//记录滑动x值
89 |
90 | this.state = {
91 | videoRate: this.defSpeed,//播放速率
92 | duration: 0.0,
93 | onload: false,//视频加载状态
94 | admRePlay: false,//重置视频进度状态
95 | opacity: new Animated.Value(1),
96 | paused: true,
97 | width: width,
98 | smallP: true,//当前是否是小屏
99 | statusBarH: 44,
100 | isEnd: false,//是否播放完了
101 | showVolume: false,
102 | showBrightness: false,
103 | videoStarTimeWidth: 0,//现在的播放时间的宽度
104 | videoEndTimeWidth: 0,//总时长的宽度
105 | height: width * 210 / 375,
106 | LinearGradientHeight: 60,//控件阴影高度
107 | topContsTop: 0,//上部分控件的top定位值
108 | bottomContsBottom: 0,//下部分控件的bottom定位值
109 | showOpenVip: false,//是否显示开通vip提示
110 | currentTime: 0.0,
111 | showLoading: false,//是否显示正在加载
112 | showConts: true,
113 | showDrTime: false,//拖动进度条时显示的时间进度
114 | showChangeList: false,//控制是否显示全屏选集
115 | showLockCont: false//锁的显示状态
116 | }
117 |
118 | this.animatedonBuffer = this.animatedonBuffer.bind(this)
119 | }
120 |
121 |
122 | componentWillUnmount() {
123 | Orientation.lockToPortrait();
124 | Platform.OS === "android"
125 | ? NativeModules.HideBottomNa.show()
126 | : NativeModules.RNIndicator.alwaysVisible();
127 | // Orientation.removeOrientationListener(this._orientationDidChange);
128 | //离开该页面 还原屏幕亮度
129 | if (this.adminBrightness) {
130 | Platform.OS === "android" ?
131 | NativeModules.AppBrightness.setAppBrightness(this.adminBrightness) :
132 | SystemSetting.setBrightnessForce(this.adminBrightness).then((success) => {
133 | !success && Alert.alert('没有权限', '您无权限改变屏幕亮度', [
134 | { 'text': '好的', style: 'cancel' },
135 | { 'text': '打开设置', onPress: () => SystemSetting.grantWriteSettingPermission() }
136 | ])
137 | });
138 | }
139 | }
140 |
141 | _orientationDidChange = (orientation) => {
142 |
143 | // if (orientation === 'LANDSCAPE') {
144 | // // 横屏
145 | // this.setAll()
146 | // } else {
147 |
148 | // this.setSmall()
149 | // // do something with portrait layout
150 | // }
151 | }
152 | //全屏
153 | changeAllBox = () => {
154 | this.setAll()
155 | Platform.OS === "android"
156 | ? NativeModules.HideBottomNa.hide()
157 | : NativeModules.RNIndicator.autoHidden();
158 | Orientation.lockToLandscape()
159 | this.props.onWindowChange && this.props.onWindowChange("full")
160 | }
161 | //小屏
162 | changeSmallBox = () => {
163 | this.setSmall()
164 | Orientation.lockToPortrait()
165 | this.props.onWindowChange && this.props.onWindowChange("small")
166 | Platform.OS === "android"
167 | ? NativeModules.HideBottomNa.show()
168 | : NativeModules.RNIndicator.alwaysVisible();
169 | }
170 |
171 |
172 | setAll = () => {
173 | this.playhideContsDotX = this.dotX.interpolate({
174 | inputRange: [0, this.state.duration],
175 | outputRange: [0, height],
176 | extrapolate: 'clamp'
177 | })
178 | this.props.navigation && this.props.navigation.setParams({ enableGestures: false });
179 | this.dotspeed && this.dotspeed.setdotStart(false)
180 | this.setState({
181 | width: height + 0,//StatusBar.currentHeight
182 | height: width,
183 | statusBarH: 0,
184 | smallP: false,
185 | showConts: false,
186 | showLockCont: false,
187 | LinearGradientHeight: 100,
188 | topContsTop: 30,
189 | bottomContsBottom: this.props.continuous ? 30 : 0,
190 |
191 | }, () => {
192 | StatusBar.setHidden(true)
193 | // 更新播放进度
194 | this.playDotX = this.dotX.interpolate({
195 | inputRange: [0, this.state.duration],
196 | outputRange: [0, height + 0 - 200],//StatusBar.currentHeight
197 | extrapolate: 'clamp'
198 | })
199 |
200 | // 更新缓存进度
201 | this.playBufferX = this.bufferX.interpolate({
202 | inputRange: [0, this.state.duration],
203 | outputRange: [0, height + 0 - 200],//StatusBar.currentHeight
204 | extrapolate: 'clamp'
205 | })
206 | })
207 | }
208 |
209 | setSmall = () => {
210 | //更新控件隐藏后的进度条
211 | this.playhideContsDotX = this.dotX.interpolate({
212 | inputRange: [0, this.state.duration],
213 | outputRange: [0, width],
214 | extrapolate: 'clamp'
215 | })
216 | this.props.navigation && this.props.navigation.setParams({ enableGestures: true });
217 | this.dotspeed && this.dotspeed.setdotStart(false)
218 | this.setState({
219 | width: width,
220 | height: width * 210 / 375,
221 | statusBarH: 0,//
222 | smallP: true,
223 | showConts: false,
224 | showLockCont: false,
225 | LinearGradientHeight: 60,
226 | topContsTop: 0,
227 | bottomContsBottom: 0,
228 |
229 | }, () => {
230 | StatusBar.setHidden(false)
231 | // 更新播放进度
232 | this.playDotX = this.dotX.interpolate({
233 | inputRange: [0, this.state.duration],
234 | outputRange: [0, width - 200],
235 | extrapolate: 'clamp'
236 | })
237 |
238 | // 更新缓存进度
239 | this.playBufferX = this.bufferX.interpolate({
240 | inputRange: [0, this.state.duration],
241 | outputRange: [0, this.state.width - 200],
242 | extrapolate: 'clamp'
243 | })
244 | }
245 | )
246 | }
247 |
248 | componentDidMount() {
249 | this.spin()
250 | if (this.props.autoPlay) {
251 | this.setState({
252 | paused: false
253 | })
254 | }
255 | // Orientation.lockToLandscape();
256 | // Orientation.addOrientationListener(this._orientationDidChange);//监听屏幕方向
257 | }
258 |
259 | //控制loading加载器的显示隐藏
260 | animatedonBuffer(event) {
261 | this.props.onBuffer && this.props.onBuffer(event)
262 | this.setState({
263 | showLoading: Platform.OS === "android" ? (event.isBuffering ? true : false) : (!this.state.paused && true)
264 | })
265 | }
266 |
267 | //播放进度 包含进度条 以及当前播放时间
268 | animatedDot = (e) => {
269 | this.props.onProgress && this.props.onProgress(e)
270 |
271 | if (!this.ismoveDot) {
272 | this.nowCurrentTime = e.currentTime
273 | }
274 |
275 | this.nowTime = formatSeconds(e.currentTime)
276 | !this.ismoveDot && this.dotspeed && this.dotspeed.setSpeed(e)
277 |
278 | if (!this.state.showOpenVip && this.props.VIPCONTS) {
279 | e.currentTime >= this.noVipSecond
280 | &&
281 | this.setState({ showOpenVip: true, paused: true, showConts: false }, () => {
282 | !this.state.smallP && this.changeSmallBox();
283 | })
284 | }
285 |
286 | this.state.showLoading && Platform.OS === "ios" && this.setState({ showLoading: false })
287 |
288 | Animated.timing(
289 | // timing方法使动画值随时间变化
290 | this.dotX, // 要变化的动画值
291 | {
292 | toValue: e.currentTime, // 最终的动画值
293 | duration: 0,
294 | useNativeDriver: false
295 | },
296 | ).start(); // 开始执行动画
297 |
298 | Animated.timing(
299 | // timing方法使动画值随时间变化
300 | this.bufferX, // 要变化的动画值
301 | {
302 | toValue: e.playableDuration, // 最终的动画值
303 | duration: 0,
304 | useNativeDriver: false
305 | },
306 | ).start(); // 开始执行动画
307 | }
308 |
309 |
310 |
311 | speedLongTouch = (evt) => {
312 | var speedStartX = evt.nativeEvent.pageX
313 | var speedTouchWidth = this.state.width / 4
314 | if ( speedStartX >= this.state.width - speedTouchWidth) {
315 |
316 | this.setState({
317 | videoRate: this.speedFastValue,
318 | speedTouch:true
319 | }, () => {
320 | this.rightSpeedRef.setNativeProps({
321 | style: {
322 | opacity: 1
323 | }
324 | })
325 | })
326 | }
327 |
328 |
329 | if(speedStartX <= speedTouchWidth ){
330 |
331 |
332 | this.isSolTouch=true
333 | this.setState({
334 | speedTouch:true
335 | })
336 | this.nowCurrentTime&&this.player.seek(this.nowCurrentTime-5)
337 | this.sloSpeedTime=setInterval(()=>{
338 |
339 | this.nowCurrentTime&&this.player.seek(this.nowCurrentTime-5)
340 | },500)
341 | this.leftSpeedRef.setNativeProps({
342 | style: {
343 | opacity: 1
344 | }
345 | })
346 | }
347 | }
348 |
349 |
350 | speedLongTouchOut = (evt) => {
351 | this.setState({
352 | speedTouch:false
353 | })
354 |
355 | var speedStartX = evt.nativeEvent.pageX
356 | var speedTouchWidth = this.state.width / 4
357 | if (speedStartX <= speedTouchWidth) {
358 | this.sloSpeedTime&&clearInterval(this.sloSpeedTime)
359 | this.isSolTouch=false
360 | this.leftSpeedRef.setNativeProps({
361 | style: {
362 | opacity: 0
363 | }
364 | })
365 |
366 | }
367 |
368 | if (speedStartX >= this.state.width - speedTouchWidth) {
369 | this.setState({
370 | videoRate: this.defSpeed
371 | }, () => {
372 | this.rightSpeedRef.setNativeProps({
373 | style: {
374 | opacity: 0
375 | }
376 | })
377 | })
378 | }
379 |
380 |
381 |
382 | }
383 |
384 |
385 | componentWillMount() {
386 |
387 | //控件逐渐透明动画
388 | this.hide = Animated.timing(
389 | // timing方法使动画值随时间变化
390 | this.state.opacity, // 要变化的动画值
391 | {
392 | toValue: 0, // 最终的动画值
393 |
394 | duration: 300,
395 | delay: 5000,
396 | useNativeDriver: false
397 | },
398 | )
399 |
400 | //控件显示动画
401 | this.AnimatedOp = Animated.timing(
402 | // timing方法使动画值随时间变化
403 | this.state.opacity, // 要变化的动画值
404 | {
405 | toValue: 1, // 最终的动画值
406 | duration: 300,
407 | useNativeDriver: false
408 | },
409 | )
410 |
411 | //控件隐藏动画
412 | this.fastHide = Animated.timing(
413 | // timing方法使动画值随时间变化
414 | this.state.opacity, // 要变化的动画值
415 | {
416 | toValue: 0, // 最终的动画值
417 | duration: 300,
418 | useNativeDriver: false
419 | },
420 | )
421 |
422 | //直接隐藏
423 | this.toofastHide = Animated.timing(
424 | // timing方法使动画值随时间变化
425 | this.state.opacity, // 要变化的动画值
426 | {
427 | toValue: 0, // 最终的动画值
428 | duration: 0,
429 | useNativeDriver: false
430 | },
431 | )
432 |
433 |
434 |
435 | // 上下滑动 调节音量 以及屏幕亮度
436 | this._panResponder = PanResponder.create({
437 | onStartShouldSetPanResponder: (evt, gestureState) => true,//锁定控件时 禁用手势
438 | onStartShouldSetPanResponderCapture: (evt, gestureState) => false,
439 | onMoveShouldSetPanResponder: (evt, gestureState) => {
440 | if(this.state.speedTouch){
441 | return false
442 | }
443 | return Math.abs(gestureState.dx) > 2 || Math.abs(gestureState.dy) > 2
444 | },
445 | onMoveShouldSetPanResponderCapture: (evt, gestureState) => {
446 | if(this.state.speedTouch){
447 | return false
448 | }
449 | return Math.abs(gestureState.dx) > 2 || Math.abs(gestureState.dy) > 2
450 | },
451 |
452 | onPanResponderGrant: (evt, gestureState) => {
453 |
454 | clearTimeout(this.TimeHideConts)//拖动时禁止隐藏控件
455 |
456 | //初始化 记录滑动的xy值
457 | this.recordHandeY = []; this.recordHandeX = [];
458 |
459 | // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
460 | this.startX = evt.nativeEvent.pageX;
461 |
462 | this.startY = evt.nativeEvent.pageY;
463 | //显示控件
464 | this.showLockAndCont()
465 |
466 | // console.log("startY", this.startY)
467 | //获取当前音量
468 | SystemSetting.getVolume().then((volume) => {
469 | this.volume = volume
470 | }).catch((err) => {
471 | console.log('Current err is ' + err);
472 | })
473 |
474 | //获取当前屏幕亮度
475 | SystemSetting.getBrightness().then((brightness) => {
476 | this.adminBrightness = brightness
477 | //安卓不是直接修改系统亮度,这里获取到的是系统亮度,所以安卓需要处理
478 | if (this.brightnessData) {
479 | this.brightness = Platform.OS === "android" ? this.brightnessData : brightness
480 | } else {
481 | this.brightness = brightness
482 | }
483 | });
484 |
485 |
486 | },
487 | onPanResponderMove: (evt, gestureState) => {
488 |
489 | if (this.recordHandeY.length < 10) {
490 | this.recordHandeY.push(evt.nativeEvent.pageY)
491 |
492 | this.recordHandeX.push(evt.nativeEvent.pageX)
493 | }
494 | // console.log("locationY", evt.nativeEvent.pageY)
495 | this.moveYData = this.startY - evt.nativeEvent.pageY
496 | if (this.LockRef && this.LockRef.state.lock||this.speedTouch) return//锁定控件时 禁用手势
497 | // console.log("moveYData",)
498 | this.moveXData = evt.nativeEvent.pageX - this.startX
499 |
500 | this.soundDataY = (this.startY + 30 - gestureState.moveY) / (this.state.height)
501 | this.BrightnessY = (this.startY + 30 - gestureState.moveY) / (this.state.height)
502 |
503 | this.speedDataX = (gestureState.moveX - this.startX)
504 |
505 | if (this.recordHandeY.length === 10) {
506 |
507 |
508 | if (Math.abs(this.recordHandeY[9] - this.recordHandeY[0]) > Math.abs(this.recordHandeX[9] - this.recordHandeX[0])) {
509 | //console.log("上下滑动")
510 | if (Math.abs(this.moveYData) > 5) {
511 |
512 | if (Math.abs(this.soundDataY) <= 1 && this.startX > this.state.width / 2) {
513 | // 改变当前系统音量
514 | if (this.soundDataY) {
515 |
516 | this.soundData = this.volume + this.soundDataY
517 | if (!this.state.showVolume) {
518 | this.setState({ showVolume: true })
519 | }
520 | if (this.hideVolumeTime) {
521 | clearTimeout(this.hideVolumeTime)
522 | }
523 | // console.log("音量", this.soundData)
524 | SystemSetting.setVolume(this.soundData);
525 | if (this.soundData >= 1) {
526 | this.VolumeRef && this.VolumeRef.setsoundWidth(100)
527 | }
528 | if (this.soundData >= 0 && this.soundData <= 1) {
529 | this.VolumeRef && this.VolumeRef.setsoundWidth(this.soundData / 1 * 100)
530 | }
531 | if (this.soundData < 0 && this.soundData <= 1 && this.state.soundWidth != 0) {
532 | this.VolumeRef && this.VolumeRef.setsoundWidth(0)
533 | }
534 | }
535 | }
536 |
537 | if (this.volume >= 1 && this.startX < this.state.width / 2 && this.soundData >= 0.96) {
538 | this.setState({
539 | soundWidth: 100
540 | })
541 | }
542 |
543 | if (Math.abs(this.BrightnessY) <= 1 && this.startX < this.state.width / 2) {
544 | //console.log("屏幕左边上下滑动调节亮度")
545 | if (this.BrightnessY) {
546 | if (!this.state.showBrightness) {
547 | this.setState({ showBrightness: true })
548 | }
549 | if (this.hideBrightnessTime) {
550 | clearTimeout(this.hideBrightnessTime)
551 | }
552 | this.brightnessData = this.brightness + this.BrightnessY
553 | if (this.brightnessData >= 1) {
554 | this.BrightnessRef && this.BrightnessRef.setBrightnessWidthFun(100)
555 | }
556 | if (this.brightnessData >= 0 && this.brightnessData <= 1) {
557 |
558 | Platform.OS === "android" ?
559 | NativeModules.AppBrightness.setAppBrightness(this.brightnessData)
560 | :
561 | SystemSetting.setBrightnessForce(this.brightnessData).then((success) => {
562 | !success && Alert.alert('没有权限', '您无权限改变屏幕亮度', [
563 | { 'text': '好的', style: 'cancel' },
564 | { 'text': '打开设置', onPress: () => SystemSetting.grantWriteSettingPermission() }
565 | ])
566 | });
567 | this.BrightnessRef && this.BrightnessRef.setBrightnessWidthFun(this.brightnessData / 1 * 100)
568 | }
569 | if (this.brightnessData < 0 && this.brightnessData <= 1 && this.state.brightnessWidth != 0) {
570 | this.BrightnessRef && this.BrightnessRef.setBrightnessWidthFun(0)
571 | }
572 | }
573 | }
574 | }
575 | } else {
576 | //"左右滑动调节播放进度"
577 | if (this.state.onload && Math.abs(this.moveXData) > 0) {
578 |
579 | const { duration, width } = this.state
580 |
581 | !this.ismoveDot && this.dotspeed && this.dotspeed.setNativeProps({
582 | style: { borderColor: "rgba(255,255,255,0.5)" }
583 | })
584 |
585 | /**调节进度开始**/
586 | !this.ismoveDot && (this.ismoveDot = true);
587 | this.dotspeed && this.dotspeed.setdotStart(true)
588 |
589 | /**调节进度结束**/
590 | this.changeSpeedTip({ opacity: 1, display: null, width: null })
591 |
592 | clearTimeout(this.TimeHideConts)//拖动进度条时禁止隐藏控件
593 | this.realMarginLeft = this.speedDataX / 2; //2为快进退的手势速度 必须大于0
594 | if (this.realMarginLeft >= width - 200) {
595 | this.realMarginLeft = width - 200
596 | }
597 | this.speedtime = duration > 60 * 30 ? (this.realMarginLeft) : (this.realMarginLeft) / (width) * duration//快进的时长 单位s
598 | this.speedalltime = getMaxdata(this.nowCurrentTime + this.speedtime, duration)
599 | this.SpeedTipTimeRef && this.SpeedTipTimeRef.setgoSpeedTime(formatSeconds(
600 | this.speedalltime
601 | ))
602 | this.dotspeedWidth = (width - 200) / duration * (this.speedalltime)
603 | this.reasut = this.dotspeedWidth
604 | this.dotspeed && this.dotspeed.setdotWidth(this.reasut)
605 | }
606 | }
607 | }
608 | },
609 | onPanResponderTerminationRequest: (evt, gestureState) => true,
610 | onPanResponderRelease: (evt, gestureState) => {
611 |
612 | this.speedLongTouchOut(evt)
613 | // this.props.navigation.setParams({ enableGestures: true });
614 | if (this.LockRef && this.LockRef.state.lock) return false//锁定控件时 禁用手势
615 |
616 | this.activateAutoHide()//激活自动隐藏
617 |
618 | this.dotspeed && this.dotspeed.setNativeProps({
619 | style: { borderColor: "rgba(255,255,255,0)" }
620 | })
621 |
622 | let speedB = '';
623 |
624 | speedB = this.speedalltime
625 | if (speedB) {
626 |
627 | speedB >= this.state.duration ?
628 | this.player.seek(speedB - 2)
629 | :
630 | this.player.seek(speedB);
631 | this.speedalltime = '';
632 | }
633 |
634 |
635 |
636 | this.changeSpeedTip({ opacity: 0, display: "none", width: 0 })
637 | this.ismoveDot = false
638 |
639 | // this.activateAutoHide()//激活自动隐藏
640 | //调节完音量后隐藏音量显示器
641 | if (this.state.showVolume) {
642 | this.hideVolumeTime = setTimeout(() => { this.setState({ showVolume: false }) }, 800)
643 | }
644 | //调节完亮度后隐藏亮度显示器
645 | if (this.state.showBrightness) {
646 | this.hideBrightnessTime = setTimeout(() => { this.setState({ showBrightness: false }) }, 800)
647 | }
648 |
649 | if (Math.abs(this.moveXData) > 5) {
650 | this.changeSpeedTip({ opacity: 0, display: "none", width: 0 })
651 | }
652 |
653 | if (this.brightnessData >= 1) {
654 | this.brightnessData = 1
655 | }
656 |
657 | if (this.brightnessData <= 0) {
658 | this.brightnessData = 0
659 | }
660 | },
661 | onPanResponderTerminate: (evt, gestureState) => {
662 | this.speedLongTouchOut(evt)
663 | this.activateAutoHide()//激活自动隐藏
664 | this.dotspeed && this.dotspeed.setNativeProps({
665 | style: { borderColor: "rgba(255,255,255,0)" }
666 | })
667 |
668 | this.changeSpeedTip({ opacity: 0, display: "none", width: 0 })
669 | this.ismoveDot = false
670 | return true;
671 | },
672 | onShouldBlockNativeResponder: (evt, gestureState) => {
673 |
674 | return false;
675 | },
676 | });
677 |
678 |
679 | // 左右拖动进度条
680 | this._panSpeeDot = PanResponder.create({
681 | onStartShouldSetPanResponder: (evt, gestureState) => true,
682 | onStartShouldSetPanResponderCapture: (evt, gestureState) => true,
683 | onMoveShouldSetPanResponder: (evt, gestureState) => true,
684 | onMoveShouldSetPanResponderCapture: (evt, gestureState) => true,
685 |
686 | onPanResponderGrant: (evt, gestureState) => {
687 | // this.props.navigation.setParams({ enableGestures: false });
688 | if (this.state.showOpenVip || !this.state.onload) return//需要权限 或者视频还不可以播放时停止不允许滑动进度条
689 | this.dotspeed.setNativeProps({
690 | style: { borderColor: this.props.dotBorderColor }
691 | })
692 | this.changeSpeedTip({ opacity: 1, display: null, width: null })
693 | clearTimeout(this.TimeHideConts)//拖动进度条时禁止隐藏控件
694 |
695 | this.ismoveDot = true
696 | // 开始手势操作。给用户一些视觉反馈,让他们知道发生了什么事情!
697 | this.touchX = evt.nativeEvent.locationX;
698 | this.dotspeed.setdotStart(true)
699 | // this.setState({ dotWidth: evt.nativeEvent.pageX - 100, })
700 | this.dotspeed.setdotWidth(evt.nativeEvent.pageX - 100)
701 | // this.playDotX=null
702 | // gestureState.{x,y} 现在会被设置为0
703 | },
704 | onPanResponderMove: (evt, gestureState) => {
705 | if (this.state.showOpenVip || !this.state.onload) return//需要权限 或者视频还不可以播放时停止不允许滑动进度条
706 | this.realMarginLeft = gestureState.moveX - this.touchX - 85;
707 | if (this.realMarginLeft >= this.state.width - 200) {
708 | this.realMarginLeft = this.state.width - 200
709 | }
710 | // console.log("realMarginLeft",this.realMarginLeft)
711 | // console.log("当前",)
712 | if (this.realMarginLeft > 0) {
713 | // this.setState({
714 |
715 | // // dotWidth: this.realMarginLeft,
716 | // //想要拖动快进的时间
717 | // goSpeedTime: formatSeconds((this.realMarginLeft) / (this.state.width - 200) * this.state.duration)
718 | // })
719 |
720 | this.SpeedTipTimeRef && this.SpeedTipTimeRef.setgoSpeedTime(formatSeconds((this.realMarginLeft) / (this.state.width - 200) * this.state.duration))
721 | this.dotspeed.setdotWidth(evt.nativeEvent.pageX - 100 >= this.state.width - 200 ? this.state.width - 200 : evt.nativeEvent.pageX - 100)
722 | }
723 | },
724 | onPanResponderTerminationRequest: (evt, gestureState) => true,
725 | onPanResponderRelease: (evt, gestureState) => {
726 | // this.props.navigation.setParams({ enableGestures: true });
727 | if (this.state.showOpenVip) return//需要权限时停止不允许滑动进度条
728 | this.dotspeed.setNativeProps({
729 | style: { borderColor: "rgba(255,255,255,0)" }
730 | })
731 | this.activateAutoHide()//手指离开后激活自动隐藏
732 | let speedB = (this.dotspeed.state.dotWidth) / (this.state.width - 200)
733 | if (speedB >= 1) {
734 | this.player.seek(this.state.duration * speedB - 2)
735 | } else {
736 | this.player.seek(this.state.duration * speedB)
737 | }
738 | this.changeSpeedTip({ opacity: 0, display: "none", width: 0 })
739 | this.ismoveDot = false
740 | },
741 | onPanResponderTerminate: (evt, gestureState) => {
742 | this.changeSpeedTip({ opacity: 0, display: "none", width: 0 })
743 | this.dotspeed.setNativeProps({
744 | style: { borderColor: "rgba(255,255,255,0)" }
745 | })
746 | this.ismoveDot = false//判断是否触摸按住进度条上的点
747 | this.activateAutoHide()//激活自动隐藏
748 | return true;
749 | },
750 | onShouldBlockNativeResponder: (evt, gestureState) => {
751 | return false;
752 | },
753 | });
754 | }
755 |
756 |
757 | changeSpeedTip = (e) => {
758 | this.SpeedTipTimeRef && this.SpeedTipTimeRef.refs.gotimeSpeed.setNativeProps({ style: e })
759 | }
760 |
761 | //快速隐藏控件
762 | fastHideConts = () => {
763 | this.fastHide.start(() => { this.setState({ showConts: false, showLockCont: false }) })
764 | }
765 |
766 | //激活自动隐藏
767 | activateAutoHide = () => {
768 | this.TimeHideConts = setTimeout(this.fastHideConts, 5000);
769 | }
770 |
771 | //重置播放
772 | rePlay = (autoPlay = true, admRePlay = true) => {
773 | this.adminPaused = true;
774 |
775 | //admRePlay//重置当前播放时间
776 |
777 | const GSTATE = { admRePlay: admRePlay, showChangeList: false }
778 |
779 | if (this.state.isEnd) {
780 |
781 | this.player.seek(0)
782 | setTimeout(() => {
783 | autoPlay
784 | ?
785 | this.setState({ paused: true, isEnd: false, showConts: true, ...GSTATE }, () => { this.setState({ paused: false }) })
786 | :
787 | this.setState({ isEnd: false, showConts: true, ...GSTATE });
788 | }, 300)
789 |
790 | } else {
791 | if (!this.state.paused) {
792 | this.setState({ paused: true, ...GSTATE }, () => { autoPlay && this.setState({ paused: false }) });
793 | }
794 | }
795 |
796 | if (this.state.paused && !this.state.isEnd) {
797 |
798 | this.setState({ paused: autoPlay ? false : true, ...GSTATE });
799 | }
800 | }
801 |
802 | //暴露方法 设置播放暂停
803 | setPaused = (e) => {
804 | this.adminPaused = true
805 | if (e) {
806 | this.setState({
807 | paused: true
808 | })
809 | } else {
810 | this.setState({
811 | paused: false
812 |
813 | })
814 | }
815 | }
816 |
817 | //重新加载 暴露方法
818 | reLoad = () => {
819 | const { paused } = this.state
820 | if (!paused) { this.setState({ paused: true }) }
821 | this.player.seek(0)
822 | setTimeout(() => {
823 | this.setState({ paused: false, showConts: true, showLoading: true });
824 | })
825 | }
826 |
827 |
828 | showLockAndCont = () => {
829 | const GSHOWSTATE = { showLockCont: true, showConts: true, showChangeList: false }
830 | const animaFun = () => {
831 | this.hide.stop(); this.AnimatedOp.stop(); this.fastHide && this.fastHide.stop();
832 | }
833 | if (this.LockRef && !this.LockRef.state.lock) {
834 | this.AnimatedOp.start(() => { this.setState({ ...GSHOWSTATE }); animaFun() }); // 开始执行动画
835 | } else {
836 | !this.LockRef
837 | ?
838 | this.AnimatedOp.start(() => { this.setState({ ...GSHOWSTATE }); animaFun() }) // 开始执行动画
839 | :
840 | this.AnimatedOp.start(() => { this.setState({ showLockCont: true, showChangeList: false }); animaFun() }); // 开始执行动画
841 | }
842 | }
843 |
844 | //显示控件
845 | showConts = () => {
846 | try {
847 | clearTimeout(this.TimeHideConts)
848 | //当提示要vip 暂停播放时 禁止双击暂停播放
849 | if (!this.state.showOpenVip) {
850 | if (this.lastBackPressed && this.lastBackPressed + 300 >= Date.now()) {
851 | // clearTimeout(this.Timeout)
852 | if (this.LockRef && this.LockRef.state.lock) return//锁定控件时 禁用手势
853 | this.adminPaused = true
854 | this.state.paused ? this.rePlay(true, false) : this.setState({ paused: true, })
855 | this.state.opacity.setValue(1)
856 | return
857 | } else {
858 | this.lastBackPressed = Date.now();
859 | }
860 | }
861 | // this.Timeout = setTimeout(() => {
862 | if (this.state.showConts || this.state.showLockCont) {//立即消失
863 | this.hide.stop()
864 | this.fastHideConts()
865 | } else {
866 | this.hide.stop();
867 | //点击视频显示控件
868 | this.showLockAndCont()
869 | }
870 | // }, 300)
871 | this.activateAutoHide()//激活控件自动隐藏
872 | } catch (error) {
873 |
874 | }
875 | }
876 |
877 |
878 | onLoad = (data) => {
879 | this.props.onLoad && this.props.onLoad(data)
880 | //视频总长度
881 | this.setState({ duration: data.duration, allTime: formatSeconds(data.duration), showChangeList: false, admRePlay: false, onload: true });
882 | //进度条动画
883 | this.playDotX = this.dotX.interpolate({
884 | inputRange: [0, data.duration],
885 | outputRange: [0, this.state.width - 200],
886 | extrapolate: 'clamp'
887 | })
888 | //隐藏控件时,最下面的进度动画
889 |
890 | this.playhideContsDotX = this.dotX.interpolate({
891 | inputRange: [0, data.duration],
892 | outputRange: [0, this.state.width],
893 | extrapolate: 'clamp'
894 | })
895 |
896 | this.playBufferX = this.bufferX.interpolate({
897 | inputRange: [0, data.duration],
898 | outputRange: [0, this.state.width - 200],
899 | extrapolate: 'clamp'
900 | })
901 | this.toofastHide.start(() => { this.setState({ showConts: false }) })
902 | }
903 |
904 |
905 | //播放完重制播放进度等状态
906 | reVideo = () => {
907 | !this.props.repeat && this.setState({ showConts: true, opacity: 1, paused: true, isEnd: true }, () => {
908 | // this.player.seek(0)
909 | // this.refs.speed.setNativeProps({
910 |
911 | // style: {
912 | // width: 0
913 | // }
914 | // })
915 | })
916 | if (!this.state.paused) {
917 | this.props.onEnd && this.props.onEnd()
918 | }
919 | }
920 |
921 | //旋转方法
922 | spin = () => {
923 | this.spinValue.setValue(0)
924 | Animated.timing(this.spinValue, {
925 | toValue: 1, // 最终值 为1,这里表示最大旋转 360度
926 | duration: 2000,
927 | easing: Easing.linear,
928 | useNativeDriver: true
929 | }).start(() => this.spin())
930 | }
931 |
932 | videoError = (e) => {
933 | this.props.onError && this.props.onError(e)
934 | this.setState({ showLoading: false, paused: true })
935 | this.onError = true
936 | }
937 | changeWindows = (e) => {
938 | if (e) {
939 | this.changeAllBox()
940 | } else {
941 | this.changeSmallBox()
942 | }
943 | }
944 |
945 | btnPasuedfun = () => {
946 | !this.state.showOpenVip && (this.adminPaused = true, this.setState({ paused: true }))
947 | }
948 |
949 | //视频地址改变的回调
950 | onchangeUrl = () => {
951 | this.setState({
952 | onload: false
953 | })
954 | }
955 |
956 | render() {
957 | const spin = this.spinValue.interpolate({
958 | inputRange: [0, 1],//输入值
959 | outputRange: ["0deg", "360deg"] //输出值
960 | })
961 | var propsObj = { ...this.props }
962 | delete (propsObj["paused"])
963 |
964 | if (this.url && this.url != this.props.url) {
965 | this.onchangeUrl()
966 | }
967 | this.url = this.props.url
968 | const { videoRate, smallP, allTime,speedTouch, LinearGradientHeight, showOpenVip, topContsTop, bottomContsBottom } = this.state
969 | const stateHeight = this.state.height
970 | const stateWidth = this.state.width
971 | const preShowSmallCont = smallP ? (this.props.showSmallCont ? true : false) : true
972 | const speedLoToWidth = stateWidth / this.speedTouchScale
973 | return (
974 | <>
975 | {this.props.statusBar ? (smallP && this.props.statusBar()) : }
976 | this.videoBox = ref} style={{ backgroundColor: "#000", position: 'relative' }}>
977 |
978 |
979 |
980 |
983 |
990 |
1042 |
1043 |
1044 | {this.state.showConts ?
1045 |
1048 | {/* 阴影 */}
1049 |
1050 | {/* 返回键 */}
1051 | {preShowSmallCont && {
1055 | if (this.state.smallP) {
1056 | this.props.onSmallBack && this.props.onSmallBack()
1057 | // this.props.navigation.goBack()
1058 | } else { this.changeSmallBox() }
1059 | }}
1060 | >
1061 |
1062 |
1066 | {this.props.backVideoName ? this.props.backVideoName : ''}
1067 |
1068 | }
1069 | {/* 收藏|更多 */}
1070 |
1071 |
1074 | {this.props.storeComponent ? this.props.storeComponent() : }
1075 |
1076 |
1079 | {this.props.moreSetting ? this.props.moreSetting() : }
1080 |
1081 |
1082 |
1083 | :
1084 | null}
1085 | {showOpenVip && this.props.VIPCONTS
1086 | &&
1087 | }
1088 | {//控件隐藏时候,最下面显示的进度
1089 | this.state.showConts ? null :
1090 |
1096 | }
1097 |
1098 | {this.props.lockControl &&
1099 | this.LockRef = ref}
1101 | showContsfun={(e) => { this.setState({ showConts: e }) }}
1102 | {...this.state}
1103 | />
1104 | }
1105 |
1106 |
1107 | {
1108 | this.state.showConts &&
1109 |
1113 | }
1114 |
1115 | {
1116 | this.state.showConts ?
1117 |
1119 |
1120 | {/* 播放暂停 */}
1121 | {
1122 | !this.props.continuous ? (this.state.paused
1123 | ?
1124 | {
1125 | if (!showOpenVip) {
1126 | this.rePlay(true, false)
1127 | }
1128 | }}>
1129 |
1130 |
1131 | :
1132 |
1133 |
1134 |
1135 | )
1136 | :
1137 | smallP && (this.state.paused
1138 | ?
1139 | {
1140 | if (!showOpenVip) {
1141 | this.rePlay(true, false)
1142 | }
1143 | }}>
1144 |
1145 |
1146 | :
1147 |
1152 |
1153 |
1154 | )
1155 |
1156 | }
1157 |
1158 | {/* 进度条 缓存条*/}
1159 | this.dotspeed = child}
1171 | playDotX={this.playDotX}
1172 | playBufferX={this.playBufferX}
1173 | ismoveDot={this.ismoveDot}
1174 | />
1175 |
1176 | {
1177 | this.state.smallP ?
1178 | { this.changeAllBox() }}
1182 | >
1183 |
1184 |
1185 | : (
1186 | !this.props.continuous &&
1187 | { this.changeSmallBox() }}
1191 | >
1192 |
1193 |
1194 | )
1195 | }
1196 |
1197 | {
1198 | !smallP &&
1199 |
1200 |
1201 | {
1202 | this.props.continuous && (this.state.paused
1203 | ?
1204 | {
1205 | if (!showOpenVip) {
1206 | this.rePlay(true, false)
1207 | }
1208 | }}>
1209 |
1210 |
1211 | :
1212 | { !showOpenVip && this.setState({ paused: true }) }}>
1213 |
1214 |
1215 | )
1216 | }
1217 | {
1218 | this.props.continuous &&
1219 | { this.props.nextBtnFun && this.props.nextBtnFun() }}
1223 | >
1224 |
1225 |
1226 | }
1227 |
1228 |
1229 | {
1230 | this.props.continuous &&
1231 | { this.setState({ showConts: false, showChangeList: true, showLockCont: false }) }}
1235 | >
1236 | 选集
1237 |
1238 | }
1239 | {
1240 | this.props.continuous &&
1241 | { this.changeSmallBox() }}
1245 | >
1246 |
1247 |
1248 | }
1249 |
1250 |
1251 |
1252 | }
1253 | {/* 阴影 */}
1254 |
1255 | :
1256 | null
1257 | }
1258 |
1259 |
1260 | {
1261 | this.SpeedTipTimeRef = ref}
1263 | {...this.state}
1264 | allTime={allTime}
1265 | />
1266 | }
1267 |
1268 | {
1269 | /* loading */
1270 |
1271 | }
1272 | {
1273 | this.adminPaused && this.state.paused &&
1274 | }
1275 |
1276 | {/* 音量 this.state.height / 2 - 20 + this.state.statusBarH / 2*/}
1277 | {
1278 | this.state.showVolume ?
1279 | this.VolumeRef = ref} {...this.state} />
1280 | :
1281 | null
1282 | }
1283 |
1284 | {/* 亮度*/
1285 | this.state.showBrightness ?
1286 | this.BrightnessRef = ref} {...this.state} />
1287 | :
1288 | null
1289 | }
1290 | {
1291 | this.state.showChangeList &&
1292 | this.props.renderAllSeenList && this.props.renderAllSeenList()
1293 | }
1294 |
1295 | >
1296 | )
1297 | }
1298 |
1299 |
1300 |
1301 | }
1302 |
1303 | const s = StyleSheet.create({
1304 | touchs: { bottom: 0, left: 5, padding: 10, zIndex: 999, }
1305 |
1306 | })
1307 |
1308 | export const NgxuSetting = function () {
1309 | this.hideAndroidBottom = () => {
1310 | if (Platform.OS == "android")
1311 | NativeModules.HideBottomNa.hide();
1312 | }
1313 | this.showAndroidBottom = () => {
1314 | if (Platform.OS == "android")
1315 | NativeModules.HideBottomNa.show();
1316 | }
1317 | this.getBrightness = (callback) => {
1318 | SystemSetting.getBrightness().then((brightness) => {
1319 | callback(brightness)
1320 | });
1321 | }
1322 | this.SetBrightness = (e) => {
1323 | Platform.OS === "android" ?
1324 | NativeModules.AppBrightness.setAppBrightness(e)
1325 | :
1326 | SystemSetting.setBrightnessForce(e).then((success) => {
1327 | !success && Alert.alert('没有权限', '您无权限改变屏幕亮度', [
1328 | { 'text': '好的', style: 'cancel' },
1329 | { 'text': '打开设置', onPress: () => SystemSetting.grantWriteSettingPermission() }
1330 | ])
1331 | });
1332 | }
1333 | }
1334 |
1335 | export default VideoPlayer
1336 |
1337 |
--------------------------------------------------------------------------------
/ios/RNIndicator.h:
--------------------------------------------------------------------------------
1 |
2 | #if __has_include("RCTBridgeModule.h")
3 | #import "RCTBridgeModule.h"
4 | #else
5 | #import
6 | #endif
7 |
8 | #import
9 |
10 |
11 |
12 | @interface HomeIndicatorView : UIViewController
13 | @property BOOL refsAutoHidden;
14 | @end
15 |
16 | @interface RNIndicator : NSObject
17 | @end
--------------------------------------------------------------------------------
/ios/RNIndicator.m:
--------------------------------------------------------------------------------
1 | #import "RNIndicator.h"
2 |
3 | @implementation HomeIndicatorView
4 |
5 | - (BOOL)prefersHomeIndicatorAutoHidden {
6 | return self.refsAutoHidden;
7 | }
8 |
9 | @end
10 |
11 |
12 | @implementation RNIndicator
13 |
14 | - (id) init {
15 | [self setrefsAutoHidden:NO];
16 | return [super init];
17 | }
18 |
19 | - (void) setrefsAutoHidden: (BOOL) newValue {
20 | HomeIndicatorView *rootViewController = [self getHomeIndicatorView];
21 |
22 | rootViewController.refsAutoHidden = newValue;
23 | if (@available(iOS 11.0, *)) {
24 | [rootViewController setNeedsUpdateOfHomeIndicatorAutoHidden];
25 | }
26 | }
27 |
28 | - (HomeIndicatorView*) getHomeIndicatorView {
29 | UIViewController *rootViewController = [UIApplication sharedApplication].delegate.window.rootViewController;
30 | NSAssert(
31 | [rootViewController isKindOfClass:[HomeIndicatorView class]],
32 | @"rootViewController is not of type HomeIndicatorView as expected."
33 | );
34 | return (HomeIndicatorView*) rootViewController;
35 | }
36 |
37 | - (dispatch_queue_t)methodQueue {
38 | return dispatch_get_main_queue();
39 | }
40 |
41 | + (BOOL)requiresMainQueueSetup {
42 | return YES;
43 | }
44 |
45 | RCT_EXPORT_MODULE()
46 |
47 | RCT_EXPORT_METHOD(alwaysVisible) {
48 | [self setrefsAutoHidden:NO];
49 | }
50 |
51 | RCT_EXPORT_METHOD(autoHidden) {
52 | [self setrefsAutoHidden:YES];
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/ios/RNIndicator.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | B3E7B58A1CC2AC0600A0062D /* RNIndicator.m in Sources */ = {isa = PBXBuildFile; fileRef = B3E7B5891CC2AC0600A0062D /* RNIndicator.m */; };
11 | /* End PBXBuildFile section */
12 |
13 | /* Begin PBXCopyFilesBuildPhase section */
14 | 58B511D91A9E6C8500147676 /* CopyFiles */ = {
15 | isa = PBXCopyFilesBuildPhase;
16 | buildActionMask = 2147483647;
17 | dstPath = "include/$(PRODUCT_NAME)";
18 | dstSubfolderSpec = 16;
19 | files = (
20 | );
21 | runOnlyForDeploymentPostprocessing = 0;
22 | };
23 | /* End PBXCopyFilesBuildPhase section */
24 |
25 | /* Begin PBXFileReference section */
26 | 134814201AA4EA6300B7C361 /* libRNIndicator.a */ = {isa = PBXFileReference; explicitFileType = archive.ar; includeInIndex = 0; path = libRNIndicator.a; sourceTree = BUILT_PRODUCTS_DIR; };
27 | B3E7B5881CC2AC0600A0062D /* RNIndicator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RNIndicator.h; sourceTree = ""; };
28 | B3E7B5891CC2AC0600A0062D /* RNIndicator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RNIndicator.m; sourceTree = ""; };
29 | /* End PBXFileReference section */
30 |
31 | /* Begin PBXFrameworksBuildPhase section */
32 | 58B511D81A9E6C8500147676 /* Frameworks */ = {
33 | isa = PBXFrameworksBuildPhase;
34 | buildActionMask = 2147483647;
35 | files = (
36 | );
37 | runOnlyForDeploymentPostprocessing = 0;
38 | };
39 | /* End PBXFrameworksBuildPhase section */
40 |
41 | /* Begin PBXGroup section */
42 | 134814211AA4EA7D00B7C361 /* Products */ = {
43 | isa = PBXGroup;
44 | children = (
45 | 134814201AA4EA6300B7C361 /* libRNIndicator.a */,
46 | );
47 | name = Products;
48 | sourceTree = "";
49 | };
50 | 58B511D21A9E6C8500147676 = {
51 | isa = PBXGroup;
52 | children = (
53 | B3E7B5881CC2AC0600A0062D /* RNIndicator.h */,
54 | B3E7B5891CC2AC0600A0062D /* RNIndicator.m */,
55 | 134814211AA4EA7D00B7C361 /* Products */,
56 | );
57 | sourceTree = "";
58 | };
59 | /* End PBXGroup section */
60 |
61 | /* Begin PBXNativeTarget section */
62 | 58B511DA1A9E6C8500147676 /* RNIndicator */ = {
63 | isa = PBXNativeTarget;
64 | buildConfigurationList = 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNIndicator" */;
65 | buildPhases = (
66 | 58B511D71A9E6C8500147676 /* Sources */,
67 | 58B511D81A9E6C8500147676 /* Frameworks */,
68 | 58B511D91A9E6C8500147676 /* CopyFiles */,
69 | );
70 | buildRules = (
71 | );
72 | dependencies = (
73 | );
74 | name = RNIndicator;
75 | productName = RCTDataManager;
76 | productReference = 134814201AA4EA6300B7C361 /* libRNIndicator.a */;
77 | productType = "com.apple.product-type.library.static";
78 | };
79 | /* End PBXNativeTarget section */
80 |
81 | /* Begin PBXProject section */
82 | 58B511D31A9E6C8500147676 /* Project object */ = {
83 | isa = PBXProject;
84 | attributes = {
85 | LastUpgradeCheck = 0830;
86 | ORGANIZATIONNAME = Facebook;
87 | TargetAttributes = {
88 | 58B511DA1A9E6C8500147676 = {
89 | CreatedOnToolsVersion = 6.1.1;
90 | };
91 | };
92 | };
93 | buildConfigurationList = 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNIndicator" */;
94 | compatibilityVersion = "Xcode 3.2";
95 | developmentRegion = English;
96 | hasScannedForEncodings = 0;
97 | knownRegions = (
98 | en,
99 | );
100 | mainGroup = 58B511D21A9E6C8500147676;
101 | productRefGroup = 58B511D21A9E6C8500147676;
102 | projectDirPath = "";
103 | projectRoot = "";
104 | targets = (
105 | 58B511DA1A9E6C8500147676 /* RNIndicator */,
106 | );
107 | };
108 | /* End PBXProject section */
109 |
110 | /* Begin PBXSourcesBuildPhase section */
111 | 58B511D71A9E6C8500147676 /* Sources */ = {
112 | isa = PBXSourcesBuildPhase;
113 | buildActionMask = 2147483647;
114 | files = (
115 | B3E7B58A1CC2AC0600A0062D /* RNIndicator.m in Sources */,
116 | );
117 | runOnlyForDeploymentPostprocessing = 0;
118 | };
119 | /* End PBXSourcesBuildPhase section */
120 |
121 | /* Begin XCBuildConfiguration section */
122 | 58B511ED1A9E6C8500147676 /* Debug */ = {
123 | isa = XCBuildConfiguration;
124 | buildSettings = {
125 | ALWAYS_SEARCH_USER_PATHS = NO;
126 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
127 | CLANG_CXX_LIBRARY = "libc++";
128 | CLANG_ENABLE_MODULES = YES;
129 | CLANG_ENABLE_OBJC_ARC = YES;
130 | CLANG_WARN_BOOL_CONVERSION = YES;
131 | CLANG_WARN_CONSTANT_CONVERSION = YES;
132 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
133 | CLANG_WARN_EMPTY_BODY = YES;
134 | CLANG_WARN_ENUM_CONVERSION = YES;
135 | CLANG_WARN_INFINITE_RECURSION = YES;
136 | CLANG_WARN_INT_CONVERSION = YES;
137 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
138 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
139 | CLANG_WARN_UNREACHABLE_CODE = YES;
140 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
141 | COPY_PHASE_STRIP = NO;
142 | ENABLE_STRICT_OBJC_MSGSEND = YES;
143 | ENABLE_TESTABILITY = YES;
144 | GCC_C_LANGUAGE_STANDARD = gnu99;
145 | GCC_DYNAMIC_NO_PIC = NO;
146 | GCC_NO_COMMON_BLOCKS = YES;
147 | GCC_OPTIMIZATION_LEVEL = 0;
148 | GCC_PREPROCESSOR_DEFINITIONS = (
149 | "DEBUG=1",
150 | "$(inherited)",
151 | );
152 | GCC_SYMBOLS_PRIVATE_EXTERN = NO;
153 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
154 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
155 | GCC_WARN_UNDECLARED_SELECTOR = YES;
156 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
157 | GCC_WARN_UNUSED_FUNCTION = YES;
158 | GCC_WARN_UNUSED_VARIABLE = YES;
159 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
160 | MTL_ENABLE_DEBUG_INFO = YES;
161 | ONLY_ACTIVE_ARCH = YES;
162 | SDKROOT = iphoneos;
163 | };
164 | name = Debug;
165 | };
166 | 58B511EE1A9E6C8500147676 /* Release */ = {
167 | isa = XCBuildConfiguration;
168 | buildSettings = {
169 | ALWAYS_SEARCH_USER_PATHS = NO;
170 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
171 | CLANG_CXX_LIBRARY = "libc++";
172 | CLANG_ENABLE_MODULES = YES;
173 | CLANG_ENABLE_OBJC_ARC = YES;
174 | CLANG_WARN_BOOL_CONVERSION = YES;
175 | CLANG_WARN_CONSTANT_CONVERSION = YES;
176 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
177 | CLANG_WARN_EMPTY_BODY = YES;
178 | CLANG_WARN_ENUM_CONVERSION = YES;
179 | CLANG_WARN_INFINITE_RECURSION = YES;
180 | CLANG_WARN_INT_CONVERSION = YES;
181 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
182 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
183 | CLANG_WARN_UNREACHABLE_CODE = YES;
184 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
185 | COPY_PHASE_STRIP = YES;
186 | ENABLE_NS_ASSERTIONS = NO;
187 | ENABLE_STRICT_OBJC_MSGSEND = YES;
188 | GCC_C_LANGUAGE_STANDARD = gnu99;
189 | GCC_NO_COMMON_BLOCKS = YES;
190 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
191 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
192 | GCC_WARN_UNDECLARED_SELECTOR = YES;
193 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
194 | GCC_WARN_UNUSED_FUNCTION = YES;
195 | GCC_WARN_UNUSED_VARIABLE = YES;
196 | IPHONEOS_DEPLOYMENT_TARGET = 8.0;
197 | MTL_ENABLE_DEBUG_INFO = NO;
198 | SDKROOT = iphoneos;
199 | VALIDATE_PRODUCT = YES;
200 | };
201 | name = Release;
202 | };
203 | 58B511F01A9E6C8500147676 /* Debug */ = {
204 | isa = XCBuildConfiguration;
205 | buildSettings = {
206 | HEADER_SEARCH_PATHS = (
207 | "$(inherited)",
208 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
209 | "$(SRCROOT)/../../../React/**",
210 | "$(SRCROOT)/../../react-native/React/**",
211 | );
212 | LIBRARY_SEARCH_PATHS = "$(inherited)";
213 | OTHER_LDFLAGS = "-ObjC";
214 | PRODUCT_NAME = RNIndicator;
215 | SKIP_INSTALL = YES;
216 | };
217 | name = Debug;
218 | };
219 | 58B511F11A9E6C8500147676 /* Release */ = {
220 | isa = XCBuildConfiguration;
221 | buildSettings = {
222 | HEADER_SEARCH_PATHS = (
223 | "$(inherited)",
224 | /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include,
225 | "$(SRCROOT)/../../../React/**",
226 | "$(SRCROOT)/../../react-native/React/**",
227 | );
228 | LIBRARY_SEARCH_PATHS = "$(inherited)";
229 | OTHER_LDFLAGS = "-ObjC";
230 | PRODUCT_NAME = RNIndicator;
231 | SKIP_INSTALL = YES;
232 | };
233 | name = Release;
234 | };
235 | /* End XCBuildConfiguration section */
236 |
237 | /* Begin XCConfigurationList section */
238 | 58B511D61A9E6C8500147676 /* Build configuration list for PBXProject "RNIndicator" */ = {
239 | isa = XCConfigurationList;
240 | buildConfigurations = (
241 | 58B511ED1A9E6C8500147676 /* Debug */,
242 | 58B511EE1A9E6C8500147676 /* Release */,
243 | );
244 | defaultConfigurationIsVisible = 0;
245 | defaultConfigurationName = Release;
246 | };
247 | 58B511EF1A9E6C8500147676 /* Build configuration list for PBXNativeTarget "RNIndicator" */ = {
248 | isa = XCConfigurationList;
249 | buildConfigurations = (
250 | 58B511F01A9E6C8500147676 /* Debug */,
251 | 58B511F11A9E6C8500147676 /* Release */,
252 | );
253 | defaultConfigurationIsVisible = 0;
254 | defaultConfigurationName = Release;
255 | };
256 | /* End XCConfigurationList section */
257 | };
258 | rootObject = 58B511D31A9E6C8500147676 /* Project object */;
259 | }
260 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "react-native-rn-videoplayer",
3 | "version": "2.2.12",
4 | "description": "A customisable React Native video player for Android and IOS",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "echo \"Error: no test specified\" && exit 1"
8 | },
9 | "repository": {
10 | "type": "git",
11 | "url": "git+https://github.com/A-ANing/react-native-rn-videoplayer.git"
12 | },
13 | "keywords": [
14 | "react-native",
15 | "react-native-video",
16 | "videoplayer",
17 | "video",
18 | "player",
19 | "gesture",
20 | "control",
21 | "volume",
22 | "brightness",
23 | "progress"
24 | ],
25 | "author": {
26 | "name": "A-ANing",
27 | "email": "839650216@qq.com"
28 | },
29 | "license": "",
30 | "homepage": "https://github.com/A-ANing/react-native-rn-videoplayer#readme",
31 | "dependencies": {
32 | "react-native-linear-gradient": "^2.5.6",
33 | "react-native-orientation-locker": "^1.1.8",
34 | "react-native-svg": "^12.1.1",
35 | "react-native-system-setting": "^1.7.2",
36 | "react-native-video": "^5.1.1"
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/utils/formatSeconds.js:
--------------------------------------------------------------------------------
1 | export const formatSeconds = (value) => {
2 | let result = parseInt(value)
3 | let h = Math.floor(result / 3600) < 10 ? '0' + Math.floor(result / 3600) : Math.floor(result / 3600)
4 | let m = Math.floor((result / 60 % 60)) < 10 ? '0' + Math.floor((result / 60 % 60)) : Math.floor((result / 60 % 60))
5 | let s = Math.floor((result % 60)) < 10 ? '0' + Math.floor((result % 60)) : Math.floor((result % 60))
6 | if (Math.floor(result / 3600) === 0) {
7 | result = `${m}:${s}`
8 | } else {
9 | result = `${h}:${m}:${s}`
10 | }
11 |
12 | return result
13 | }
14 |
--------------------------------------------------------------------------------
/utils/getMaxdata.js:
--------------------------------------------------------------------------------
1 | export const getMaxdata=(a,b)=>{
2 | if(a<=0){
3 | return 0
4 | }
5 | if(a>=b){
6 | return b
7 | }
8 | return a
9 | }
--------------------------------------------------------------------------------
/view/index.js:
--------------------------------------------------------------------------------
1 | import React, { Component } from 'react';
2 | import {
3 | Text,
4 | StyleSheet,
5 | TouchableOpacity,
6 | View,
7 | Dimensions,
8 | Animated,
9 | StatusBar,
10 | Platform,
11 | SafeAreaView
12 | } from 'react-native';
13 | import {
14 | SvgVideoUnlock,
15 | SvgVideoLocking,
16 | SvgVideoLoading,
17 | SvgVideoBrightness,
18 | SvgVideoNoSound,
19 | SvgVideoStop,
20 | SvgVideoSound,
21 | SvgVideoFastSpeed
22 | } from '../component/svg'
23 | import { formatSeconds } from '../utils/formatSeconds'
24 |
25 | const { height, width } = Dimensions.get('screen');
26 |
27 |
28 |
29 |
30 | export const Loading = (props) => {
31 |
32 | return (
33 | <>
34 |
35 | {
36 | props.showLoading ?
37 |
45 |
52 |
53 | {
54 | props.loadingIcon
55 | ?
56 | props.loadingIcon
57 | :
58 |
59 | }
60 |
61 |
62 | {props.loadingText ? props.loadingText : "正在缓冲..."}
63 |
64 |
65 | :
66 | null
67 | }
68 | >
69 |
70 | )
71 |
72 | }
73 |
74 |
75 | //锁定
76 | export class Lock extends Component {
77 | state = {
78 | lock: false
79 | }
80 | onChangeLock = () => {
81 |
82 | this.props.showContsfun(this.state.lock)
83 |
84 | this.setState({
85 | lock: !this.state.lock
86 | })
87 | }
88 | render() {
89 | const { props } = this
90 | const { lock } = this.state
91 | if (props.showLockCont) {
92 | return (
93 |
101 |
108 | {
109 | lock ? :
110 | }
111 |
112 |
113 | )
114 | } else {
115 | return null
116 | }
117 |
118 | }
119 |
120 | }
121 |
122 |
123 | //暂停的tips
124 | export const TipsPaused = (props) => {
125 | let timer = ''
126 | const [animater, setAnimater] = React.useState(new Animated.Value(0))
127 | const [show, setShow] = React.useState(true)
128 |
129 | React.useEffect(() => {
130 |
131 | tipsPausedFun();
132 |
133 | }, [])
134 |
135 |
136 | //控件显示动画
137 | const AnimatedOp = Animated.timing(
138 | // timing方法使动画值随时间变化
139 | animater, // 要变化的动画值
140 | {
141 | toValue: 1, // 最终的动画值
142 | duration: 300,
143 | useNativeDriver: false
144 | },
145 | )
146 |
147 | function tipsPausedFun() {
148 | if (AnimatedOp) {
149 | AnimatedOp.stop()
150 | }
151 | if (timer) {
152 | clearTimeout(timer)
153 | }
154 | AnimatedOp.start(() => {
155 | timer = setTimeout(() => {
156 | setShow(false)
157 | }, 2000)
158 | });
159 | }
160 |
161 | if (show) {
162 | return
163 |
164 | {props.pausedTipText ? props.pausedTipText : "已暂停"}
165 |
166 | } else {
167 | return null
168 | }
169 |
170 |
171 | }
172 |
173 |
174 |
175 | //亮度
176 | export class Brightness extends Component {
177 | constructor(props) {
178 | super(props)
179 | this.state = {
180 | brightnessWidth: 0
181 | }
182 | }
183 |
184 | setBrightnessWidthFun = (data) => {
185 | this.setState({
186 | brightnessWidth: data
187 | })
188 | }
189 | render() {
190 | const { props } = this
191 | const { brightnessWidth } = this.state
192 | return (
193 |
198 |
206 |
207 |
208 |
209 |
210 |
211 |
212 | )
213 | }
214 | }
215 |
216 | //音量
217 |
218 | export class Volume extends Component {
219 | state = {
220 | soundWidth: 0.1
221 | }
222 |
223 | setsoundWidth = (soundWidth) => {
224 | this.setState({
225 | soundWidth
226 | })
227 | }
228 | render() {
229 | const { props } = this
230 | const { soundWidth } = this.state
231 |
232 | return (
233 |
238 |
242 | {
243 | soundWidth > 0 ? :
244 | }
245 |
246 |
247 |
248 |
249 |
250 | )
251 | }
252 | }
253 |
254 |
255 |
256 | export const BottomSpeed = (props) => {
257 |
258 | return (
259 |
260 |
261 |
262 |
263 |
264 | {/* 进度条*/}
265 |
266 |
267 |
268 |
269 |
270 |
271 |
272 |
273 | )
274 | }
275 |
276 |
277 |
278 |
279 | export const Header = (props) => {
280 | return (
281 | <>
282 | {
283 | props.width === width && Platform.OS === "android" ?
284 |
285 | :
286 |
287 | }
288 |
289 | >
290 | )
291 |
292 | }
293 |
294 | var animationT = 0;
295 | var animationN = 5;
296 | var animationM = 2;
297 | export class AnFastSvg extends Component {
298 |
299 | state={
300 | fV:new Animated.Value(0),
301 | sV:new Animated.Value(0)
302 |
303 | }
304 |
305 |
306 | componentDidMount() {
307 | animationT = 0;
308 | this.anmin = requestAnimationFrame(this.loopAnimation);
309 |
310 | }
311 |
312 | componentWillUnmount(){
313 | this.cancelAnim()
314 | }
315 |
316 |
317 |
318 |
319 | loopAnimation = () => {
320 |
321 | var t0 = animationT, t1 = t0 + 10
322 | var v1 = Number(Math.cos(t0).toFixed(2)) * animationN + animationM;
323 | var v2 = Number(Math.cos(t1).toFixed(2)) * animationN + animationM;
324 |
325 | this.setState({
326 | fV: v1,
327 | sV: v2,
328 |
329 |
330 | });
331 | animationT += 0.25;
332 | this.anmin&&cancelAnimationFrame(this.anmin)
333 | this.anmin = requestAnimationFrame(this.loopAnimation);
334 | }
335 |
336 | cancelAnim() {
337 | cancelAnimationFrame(this.anmin)
338 | }
339 |
340 | render() {
341 | const {fV , sV} =this.state
342 | const {isSolTouch,videoRate,solText="快退中...",fastText="快进中..."} = this.props
343 | return (
344 | <>
345 |
346 |
347 |
348 |
349 |
350 |
351 |
352 |
353 |
354 |
355 |
356 |
357 | {isSolTouch?solText:`${videoRate}x ${fastText}`}
358 | >
359 | )
360 | }
361 |
362 |
363 | }
364 |
365 |
366 | export class Speed extends Component {
367 | state = {
368 | allTime: "00:00",//总时长
369 | nowTime: "00:00",//当前播放时长
370 | dotStart: false,//是否按住了进度条上的点
371 | dotWidth: 0
372 | }
373 | setNativeProps = (data) => {
374 | this.refs.dotspeed.setNativeProps(data)
375 | }
376 |
377 | setdotWidth = (dotWidth) => {
378 | this.setState({ dotWidth })
379 | }
380 |
381 |
382 |
383 |
384 | setSpeed = (e) => {
385 | if (this.nowTime != parseInt(e.currentTime)) {
386 | this.nowTime = parseInt(e.currentTime)
387 |
388 | this.props.ismoveDot ?
389 | this.setState({
390 | nowTime: formatSeconds(e.currentTime),
391 |
392 | })
393 | :
394 | this.setState({
395 | nowTime: formatSeconds(e.currentTime),
396 | dotStart: false
397 | })
398 | }
399 | }
400 |
401 | setdotStart = (e) => {
402 | const dotStart = this.state.dotStart
403 | if (e && !dotStart) {
404 | this.setState({ dotStart: true })
405 | }
406 |
407 | if (!e && dotStart) {
408 | this.setState({ dotStart: false })
409 | }
410 | }
411 |
412 | render() {
413 | const { props } = this
414 | const { nowTime, dotStart, dotWidth } = this.state
415 | return (
416 |
417 |
418 | {props.admRePlay ? "00:00" : (nowTime == "00:00" ? props.nowTime : nowTime)}
419 |
420 |
421 |
422 | {/* 进度条*/}
423 |
424 | {/* 缓存条*/}
425 |
426 | {/* 进度条上的点 */}
427 |
428 |
429 |
430 | {/* 总进度 */}
431 |
432 |
433 |
434 |
435 | {props.admRePlay ? "00:00" : props.allTime}
436 |
437 |
438 | )
439 | }
440 | }
441 |
442 | /* 拖动进度条展示拖动当前时时间 */
443 | export class SpeedTipTime extends Component {
444 | state = {
445 | goSpeedTime: "00:00",//想要拖动改变的进度时常
446 |
447 |
448 | }
449 |
450 | setgoSpeedTime = (goSpeedTime) => {
451 | this.setState({ goSpeedTime })
452 | }
453 |
454 | render() {
455 | const { props } = this
456 | return (
457 |
465 |
469 | {this.state.goSpeedTime}
470 | /
471 | {props.allTime}
472 |
473 |
474 | )
475 | }
476 | }
477 |
478 |
479 |
480 | const styles = StyleSheet.create({
481 |
482 | TipsPausedBox: {
483 | flexDirection: "row", backgroundColor: "rgba(0,0,0,0.8)", borderRadius: 4, paddingVertical: 6, paddingHorizontal: 8, position: "absolute", alignItems: "center"
484 | },
485 | TipsPausedText: {
486 | color: "#fff", fontSize: 14, paddingLeft: 5
487 | }
488 | })
--------------------------------------------------------------------------------