├── .classpath
├── .project
├── AndroidManifest.xml
├── README.md
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── proguard-project.txt
├── project.properties
├── res
├── anim
│ ├── option_entry_from_bottom.xml
│ ├── option_entry_from_top.xml
│ ├── option_leave_from_bottom.xml
│ └── option_leave_from_top.xml
├── drawable-hdpi
│ ├── ic_launcher.png
│ ├── line_point.png
│ ├── ling.png
│ ├── top_btnback.png
│ ├── video_btn_down.png
│ ├── video_btn_on.png
│ ├── video_line01.png
│ └── video_line02.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xhdpi
│ └── ic_launcher.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── drawable
│ └── seekbar.xml
├── layout
│ ├── activity_main.xml
│ └── vv.xml
├── menu
│ └── main.xml
├── values-sw600dp
│ └── dimens.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
└── src
└── com
└── jit
└── video
├── DensityUtil.java
├── FullScreenVideoView.java
├── LightnessController.java
├── MainActivity.java
├── VolumnController.java
└── VolumnView.java
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | MainActivity
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
12 |
13 |
14 |
19 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | AndroidVideoView
2 | ================
3 |
4 |
5 | ## 功能介绍
6 | * Android自定义全屏VideoView,仿主流视频客户端,左右滑屏快退快进
7 | * 上下滑屏,手指在左半屏时,调整亮度
8 | * 上下滑屏,手指在右半屏时,调整音量
9 | * 横竖屏无缝自动切换
10 |
11 | ## 扩展
12 | 如果你有好的实现或者功能扩展,请提交Pull Request。
13 | 如果你有好的想法,请在我的微信公众账号留言,我来实现你的想法。
14 |
15 | ## 交流
16 | * 微信公众账号:Android干货分享(ID:android_share)
17 | * 技术交流QQ群:318588906,欢迎大家加群
18 | * [开源中国博客](http://my.oschina.net/jack1900/blog)
19 | * 邮件(jack_1900@163.com)
20 |
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/anim/option_entry_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/res/anim/option_entry_from_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/res/anim/option_leave_from_bottom.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/res/anim/option_leave_from_top.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
10 |
15 |
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/line_point.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/line_point.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ling.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/ling.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/top_btnback.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/top_btnback.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/video_btn_down.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/video_btn_down.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/video_btn_on.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/video_btn_on.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/video_line01.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/video_line01.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/video_line02.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-hdpi/video_line02.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/JackCho/AndroidVideoView/dde4805cf7a589ea3afe9b56545d86dc9c81fd52/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable/seekbar.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
12 |
13 |
17 |
18 |
23 |
24 |
33 |
34 |
35 |
36 |
42 |
43 |
50 |
51 |
62 |
63 |
74 |
75 |
89 |
91 |
92 |
93 |
--------------------------------------------------------------------------------
/res/layout/vv.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
10 |
11 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
10 |
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
10 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
13 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | FullVideoDemo
5 | Settings
6 | Hello world!
7 |
8 |
9 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/com/jit/video/DensityUtil.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import android.content.Context;
4 |
5 | public class DensityUtil {
6 |
7 | public static final float getHeightInPx(Context context) {
8 | final float height = context.getResources().getDisplayMetrics().heightPixels;
9 | return height;
10 | }
11 |
12 | public static final float getWidthInPx(Context context) {
13 | final float width = context.getResources().getDisplayMetrics().widthPixels;
14 | return width;
15 | }
16 |
17 | public static final int getHeightInDp(Context context) {
18 | final float height = context.getResources().getDisplayMetrics().heightPixels;
19 | int heightInDp = px2dip(context, height);
20 | return heightInDp;
21 | }
22 |
23 | public static final int getWidthInDp(Context context) {
24 | final float height = context.getResources().getDisplayMetrics().heightPixels;
25 | int widthInDp = px2dip(context, height);
26 | return widthInDp;
27 | }
28 |
29 | public static int dip2px(Context context, float dpValue) {
30 | final float scale = context.getResources().getDisplayMetrics().density;
31 | return (int) (dpValue * scale + 0.5f);
32 | }
33 |
34 | public static int px2dip(Context context, float pxValue) {
35 | final float scale = context.getResources().getDisplayMetrics().density;
36 | return (int) (pxValue / scale + 0.5f);
37 | }
38 |
39 | public static int px2sp(Context context, float pxValue) {
40 | final float scale = context.getResources().getDisplayMetrics().density;
41 | return (int) (pxValue / scale + 0.5f);
42 | }
43 |
44 | public static int sp2px(Context context, float spValue) {
45 | final float scale = context.getResources().getDisplayMetrics().density;
46 | return (int) (spValue * scale + 0.5f);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/src/com/jit/video/FullScreenVideoView.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.widget.VideoView;
6 |
7 | /**
8 | * 自动全屏的VideoView
9 | */
10 | public class FullScreenVideoView extends VideoView {
11 |
12 | private int videoWidth;
13 | private int videoHeight;
14 |
15 | public FullScreenVideoView(Context context) {
16 | super(context);
17 | }
18 |
19 | public FullScreenVideoView(Context context, AttributeSet attrs) {
20 | super(context, attrs);
21 | }
22 |
23 | public FullScreenVideoView(Context context, AttributeSet attrs, int defStyle) {
24 | super(context, attrs, defStyle);
25 | }
26 |
27 | @Override
28 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
29 | int width = getDefaultSize(videoWidth, widthMeasureSpec);
30 | int height = getDefaultSize(videoHeight, heightMeasureSpec);
31 | if (videoWidth > 0 && videoHeight > 0) {
32 | if (videoWidth * height > width * videoHeight) {
33 | height = width * videoHeight / videoWidth;
34 | } else if (videoWidth * height < width * videoHeight) {
35 | width = height * videoWidth / videoHeight;
36 | }
37 | }
38 | setMeasuredDimension(width, height);
39 | }
40 |
41 | public int getVideoWidth() {
42 | return videoWidth;
43 | }
44 |
45 | public void setVideoWidth(int videoWidth) {
46 | this.videoWidth = videoWidth;
47 | }
48 |
49 | public int getVideoHeight() {
50 | return videoHeight;
51 | }
52 |
53 | public void setVideoHeight(int videoHeight) {
54 | this.videoHeight = videoHeight;
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/src/com/jit/video/LightnessController.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import android.app.Activity;
4 | import android.content.ContentResolver;
5 | import android.provider.Settings;
6 | import android.view.WindowManager;
7 | import android.widget.Toast;
8 | import android.provider.Settings.System;
9 |
10 | public class LightnessController {
11 |
12 | // 判断是否开启了自动亮度调节
13 | public static boolean isAutoBrightness(Activity act) {
14 | boolean automicBrightness = false;
15 | ContentResolver aContentResolver = act.getContentResolver();
16 | try {
17 | automicBrightness = Settings.System.getInt(aContentResolver,
18 | Settings.System.SCREEN_BRIGHTNESS_MODE) == Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC;
19 | } catch (Exception e) {
20 | Toast.makeText(act, "无法获取亮度", Toast.LENGTH_SHORT).show();
21 | }
22 | return automicBrightness;
23 | }
24 |
25 | // 改变亮度
26 | public static void setLightness(Activity act, int value) {
27 | try {
28 | System.putInt(act.getContentResolver(), System.SCREEN_BRIGHTNESS, value);
29 | WindowManager.LayoutParams lp = act.getWindow().getAttributes();
30 | lp.screenBrightness = (value <= 0 ? 1 : value) / 255f;
31 | act.getWindow().setAttributes(lp);
32 | } catch (Exception e) {
33 | Toast.makeText(act, "无法改变亮度", Toast.LENGTH_SHORT).show();
34 | }
35 | }
36 |
37 | // 获取亮度
38 | public static int getLightness(Activity act) {
39 | return System.getInt(act.getContentResolver(), System.SCREEN_BRIGHTNESS, -1);
40 | }
41 |
42 | // 停止自动亮度调节
43 | public static void stopAutoBrightness(Activity activity) {
44 | Settings.System.putInt(activity.getContentResolver(),
45 | Settings.System.SCREEN_BRIGHTNESS_MODE,
46 | Settings.System.SCREEN_BRIGHTNESS_MODE_MANUAL);
47 | }
48 |
49 | // 开启亮度自动调节
50 | public static void startAutoBrightness(Activity activity) {
51 | Settings.System.putInt(activity.getContentResolver(),
52 | Settings.System.SCREEN_BRIGHTNESS_MODE,
53 | Settings.System.SCREEN_BRIGHTNESS_MODE_AUTOMATIC);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/com/jit/video/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import java.text.DateFormat;
4 | import java.text.SimpleDateFormat;
5 | import java.util.Date;
6 | import java.util.Timer;
7 | import java.util.TimerTask;
8 |
9 | import android.annotation.SuppressLint;
10 | import android.app.Activity;
11 | import android.content.Context;
12 | import android.content.res.Configuration;
13 | import android.media.AudioManager;
14 | import android.media.MediaPlayer;
15 | import android.media.MediaPlayer.OnCompletionListener;
16 | import android.media.MediaPlayer.OnPreparedListener;
17 | import android.os.Bundle;
18 | import android.os.Handler;
19 | import android.os.Message;
20 | import android.view.MotionEvent;
21 | import android.view.View;
22 | import android.view.View.OnClickListener;
23 | import android.view.View.OnTouchListener;
24 | import android.view.animation.Animation;
25 | import android.view.animation.Animation.AnimationListener;
26 | import android.view.animation.AnimationUtils;
27 | import android.widget.ImageView;
28 | import android.widget.SeekBar;
29 | import android.widget.SeekBar.OnSeekBarChangeListener;
30 | import android.widget.TextView;
31 |
32 | public class MainActivity extends Activity implements OnClickListener {
33 |
34 | // 自定义VideoView
35 | private FullScreenVideoView mVideo;
36 |
37 | // 头部View
38 | private View mTopView;
39 |
40 | // 底部View
41 | private View mBottomView;
42 | // 视频播放拖动条
43 | private SeekBar mSeekBar;
44 | private ImageView mPlay;
45 | private TextView mPlayTime;
46 | private TextView mDurationTime;
47 |
48 | // 音频管理器
49 | private AudioManager mAudioManager;
50 |
51 | // 屏幕宽高
52 | private float width;
53 | private float height;
54 |
55 | // 视频播放时间
56 | private int playTime;
57 |
58 | private String videoUrl = "http://www.ydtsystem.com/CardImage/21/video/20140305/20140305124807_37734.mp4";
59 | // 自动隐藏顶部和底部View的时间
60 | private static final int HIDE_TIME = 5000;
61 |
62 | // 声音调节Toast
63 | private VolumnController volumnController;
64 |
65 | // 原始屏幕亮度
66 | private int orginalLight;
67 |
68 | @Override
69 | protected void onCreate(Bundle savedInstanceState) {
70 | super.onCreate(savedInstanceState);
71 | setContentView(R.layout.activity_main);
72 | volumnController = new VolumnController(this);
73 | mVideo = (FullScreenVideoView) findViewById(R.id.videoview);
74 | mPlayTime = (TextView) findViewById(R.id.play_time);
75 | mDurationTime = (TextView) findViewById(R.id.total_time);
76 | mPlay = (ImageView) findViewById(R.id.play_btn);
77 | mSeekBar = (SeekBar) findViewById(R.id.seekbar);
78 | mTopView = findViewById(R.id.top_layout);
79 | mBottomView = findViewById(R.id.bottom_layout);
80 |
81 | mAudioManager = (AudioManager) getSystemService(Context.AUDIO_SERVICE);
82 |
83 | width = DensityUtil.getWidthInPx(this);
84 | height = DensityUtil.getHeightInPx(this);
85 | threshold = DensityUtil.dip2px(this, 18);
86 |
87 | orginalLight = LightnessController.getLightness(this);
88 |
89 | mPlay.setOnClickListener(this);
90 | mSeekBar.setOnSeekBarChangeListener(mSeekBarChangeListener);
91 |
92 | playVideo();
93 | }
94 |
95 | @Override
96 | public void onConfigurationChanged(Configuration newConfig) {
97 | if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_LANDSCAPE) {
98 | height = DensityUtil.getWidthInPx(this);
99 | width = DensityUtil.getHeightInPx(this);
100 | } else if (this.getResources().getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
101 | width = DensityUtil.getWidthInPx(this);
102 | height = DensityUtil.getHeightInPx(this);
103 | }
104 | super.onConfigurationChanged(newConfig);
105 | }
106 |
107 | @Override
108 | protected void onPause() {
109 | super.onPause();
110 | LightnessController.setLightness(this, orginalLight);
111 | }
112 |
113 | private OnSeekBarChangeListener mSeekBarChangeListener = new OnSeekBarChangeListener() {
114 |
115 | @Override
116 | public void onStopTrackingTouch(SeekBar seekBar) {
117 | mHandler.postDelayed(hideRunnable, HIDE_TIME);
118 | }
119 |
120 | @Override
121 | public void onStartTrackingTouch(SeekBar seekBar) {
122 | mHandler.removeCallbacks(hideRunnable);
123 | }
124 |
125 | @Override
126 | public void onProgressChanged(SeekBar seekBar, int progress,
127 | boolean fromUser) {
128 | if (fromUser) {
129 | int time = progress * mVideo.getDuration() / 100;
130 | mVideo.seekTo(time);
131 | }
132 | }
133 | };
134 |
135 | private void backward(float delataX) {
136 | int current = mVideo.getCurrentPosition();
137 | int backwardTime = (int) (delataX / width * mVideo.getDuration());
138 | int currentTime = current - backwardTime;
139 | mVideo.seekTo(currentTime);
140 | mSeekBar.setProgress(currentTime * 100 / mVideo.getDuration());
141 | mPlayTime.setText(formatTime(currentTime));
142 | }
143 |
144 | private void forward(float delataX) {
145 | int current = mVideo.getCurrentPosition();
146 | int forwardTime = (int) (delataX / width * mVideo.getDuration());
147 | int currentTime = current + forwardTime;
148 | mVideo.seekTo(currentTime);
149 | mSeekBar.setProgress(currentTime * 100 / mVideo.getDuration());
150 | mPlayTime.setText(formatTime(currentTime));
151 | }
152 |
153 | private void volumeDown(float delatY) {
154 | int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
155 | int current = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
156 | int down = (int) (delatY / height * max * 3);
157 | int volume = Math.max(current - down, 0);
158 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
159 | int transformatVolume = volume * 100 / max;
160 | volumnController.show(transformatVolume);
161 | }
162 |
163 | private void volumeUp(float delatY) {
164 | int max = mAudioManager.getStreamMaxVolume(AudioManager.STREAM_MUSIC);
165 | int current = mAudioManager.getStreamVolume(AudioManager.STREAM_MUSIC);
166 | int up = (int) ((delatY / height) * max * 3);
167 | int volume = Math.min(current + up, max);
168 | mAudioManager.setStreamVolume(AudioManager.STREAM_MUSIC, volume, 0);
169 | int transformatVolume = volume * 100 / max;
170 | volumnController.show(transformatVolume);
171 | }
172 |
173 | private void lightDown(float delatY) {
174 | int down = (int) (delatY / height * 255 * 3);
175 | int transformatLight = LightnessController.getLightness(this) - down;
176 | LightnessController.setLightness(this, transformatLight);
177 | }
178 |
179 | private void lightUp(float delatY) {
180 | int up = (int) (delatY / height * 255 * 3);
181 | int transformatLight = LightnessController.getLightness(this) + up;
182 | LightnessController.setLightness(this, transformatLight);
183 | }
184 |
185 | @Override
186 | protected void onDestroy() {
187 | super.onDestroy();
188 | mHandler.removeMessages(0);
189 | mHandler.removeCallbacksAndMessages(null);
190 | }
191 |
192 | @SuppressLint("HandlerLeak")
193 | private Handler mHandler = new Handler() {
194 |
195 | @Override
196 | public void handleMessage(Message msg) {
197 | super.handleMessage(msg);
198 | switch (msg.what) {
199 | case 1:
200 | if (mVideo.getCurrentPosition() > 0) {
201 | mPlayTime.setText(formatTime(mVideo.getCurrentPosition()));
202 | int progress = mVideo.getCurrentPosition() * 100 / mVideo.getDuration();
203 | mSeekBar.setProgress(progress);
204 | if (mVideo.getCurrentPosition() > mVideo.getDuration() - 100) {
205 | mPlayTime.setText("00:00");
206 | mSeekBar.setProgress(0);
207 | }
208 | mSeekBar.setSecondaryProgress(mVideo.getBufferPercentage());
209 | } else {
210 | mPlayTime.setText("00:00");
211 | mSeekBar.setProgress(0);
212 | }
213 |
214 | break;
215 | case 2:
216 | showOrHide();
217 | break;
218 |
219 | default:
220 | break;
221 | }
222 | }
223 | };
224 |
225 | private void playVideo() {
226 | mVideo.setVideoPath(videoUrl);
227 | mVideo.requestFocus();
228 | mVideo.setOnPreparedListener(new OnPreparedListener() {
229 | @Override
230 | public void onPrepared(MediaPlayer mp) {
231 | mVideo.setVideoWidth(mp.getVideoWidth());
232 | mVideo.setVideoHeight(mp.getVideoHeight());
233 |
234 | mVideo.start();
235 | if (playTime != 0) {
236 | mVideo.seekTo(playTime);
237 | }
238 |
239 | mHandler.removeCallbacks(hideRunnable);
240 | mHandler.postDelayed(hideRunnable, HIDE_TIME);
241 | mDurationTime.setText(formatTime(mVideo.getDuration()));
242 | Timer timer = new Timer();
243 | timer.schedule(new TimerTask() {
244 |
245 | @Override
246 | public void run() {
247 | mHandler.sendEmptyMessage(1);
248 | }
249 | }, 0, 1000);
250 | }
251 | });
252 | mVideo.setOnCompletionListener(new OnCompletionListener() {
253 | @Override
254 | public void onCompletion(MediaPlayer mp) {
255 | mPlay.setImageResource(R.drawable.video_btn_down);
256 | mPlayTime.setText("00:00");
257 | mSeekBar.setProgress(0);
258 | }
259 | });
260 | mVideo.setOnTouchListener(mTouchListener);
261 | }
262 |
263 | private Runnable hideRunnable = new Runnable() {
264 |
265 | @Override
266 | public void run() {
267 | showOrHide();
268 | }
269 | };
270 |
271 | @SuppressLint("SimpleDateFormat")
272 | private String formatTime(long time) {
273 | DateFormat formatter = new SimpleDateFormat("mm:ss");
274 | return formatter.format(new Date(time));
275 | }
276 |
277 | private float mLastMotionX;
278 | private float mLastMotionY;
279 | private int startX;
280 | private int startY;
281 | private int threshold;
282 | private boolean isClick = true;
283 |
284 | private OnTouchListener mTouchListener = new OnTouchListener() {
285 |
286 | @Override
287 | public boolean onTouch(View v, MotionEvent event) {
288 | final float x = event.getX();
289 | final float y = event.getY();
290 |
291 | switch (event.getAction()) {
292 | case MotionEvent.ACTION_DOWN:
293 | mLastMotionX = x;
294 | mLastMotionY = y;
295 | startX = (int) x;
296 | startY = (int) y;
297 | break;
298 | case MotionEvent.ACTION_MOVE:
299 | float deltaX = x - mLastMotionX;
300 | float deltaY = y - mLastMotionY;
301 | float absDeltaX = Math.abs(deltaX);
302 | float absDeltaY = Math.abs(deltaY);
303 | // 声音调节标识
304 | boolean isAdjustAudio = false;
305 | if (absDeltaX > threshold && absDeltaY > threshold) {
306 | if (absDeltaX < absDeltaY) {
307 | isAdjustAudio = true;
308 | } else {
309 | isAdjustAudio = false;
310 | }
311 | } else if (absDeltaX < threshold && absDeltaY > threshold) {
312 | isAdjustAudio = true;
313 | } else if (absDeltaX > threshold && absDeltaY < threshold) {
314 | isAdjustAudio = false;
315 | } else {
316 | return true;
317 | }
318 | if (isAdjustAudio) {
319 | if (x < width / 2) {
320 | if (deltaY > 0) {
321 | lightDown(absDeltaY);
322 | } else if (deltaY < 0) {
323 | lightUp(absDeltaY);
324 | }
325 | } else {
326 | if (deltaY > 0) {
327 | volumeDown(absDeltaY);
328 | } else if (deltaY < 0) {
329 | volumeUp(absDeltaY);
330 | }
331 | }
332 |
333 | } else {
334 | if (deltaX > 0) {
335 | forward(absDeltaX);
336 | } else if (deltaX < 0) {
337 | backward(absDeltaX);
338 | }
339 | }
340 | mLastMotionX = x;
341 | mLastMotionY = y;
342 | break;
343 | case MotionEvent.ACTION_UP:
344 | if (Math.abs(x - startX) > threshold
345 | || Math.abs(y - startY) > threshold) {
346 | isClick = false;
347 | }
348 | mLastMotionX = 0;
349 | mLastMotionY = 0;
350 | startX = (int) 0;
351 | if (isClick) {
352 | showOrHide();
353 | }
354 | isClick = true;
355 | break;
356 |
357 | default:
358 | break;
359 | }
360 | return true;
361 | }
362 |
363 | };
364 |
365 | @Override
366 | public void onClick(View v) {
367 | switch (v.getId()) {
368 | case R.id.play_btn:
369 | if (mVideo.isPlaying()) {
370 | mVideo.pause();
371 | mPlay.setImageResource(R.drawable.video_btn_down);
372 | } else {
373 | mVideo.start();
374 | mPlay.setImageResource(R.drawable.video_btn_on);
375 | }
376 | break;
377 | default:
378 | break;
379 | }
380 | }
381 |
382 | private void showOrHide() {
383 | if (mTopView.getVisibility() == View.VISIBLE) {
384 | mTopView.clearAnimation();
385 | Animation animation = AnimationUtils.loadAnimation(this,
386 | R.anim.option_leave_from_top);
387 | animation.setAnimationListener(new AnimationImp() {
388 | @Override
389 | public void onAnimationEnd(Animation animation) {
390 | super.onAnimationEnd(animation);
391 | mTopView.setVisibility(View.GONE);
392 | }
393 | });
394 | mTopView.startAnimation(animation);
395 |
396 | mBottomView.clearAnimation();
397 | Animation animation1 = AnimationUtils.loadAnimation(this,
398 | R.anim.option_leave_from_bottom);
399 | animation1.setAnimationListener(new AnimationImp() {
400 | @Override
401 | public void onAnimationEnd(Animation animation) {
402 | super.onAnimationEnd(animation);
403 | mBottomView.setVisibility(View.GONE);
404 | }
405 | });
406 | mBottomView.startAnimation(animation1);
407 | } else {
408 | mTopView.setVisibility(View.VISIBLE);
409 | mTopView.clearAnimation();
410 | Animation animation = AnimationUtils.loadAnimation(this,
411 | R.anim.option_entry_from_top);
412 | mTopView.startAnimation(animation);
413 |
414 | mBottomView.setVisibility(View.VISIBLE);
415 | mBottomView.clearAnimation();
416 | Animation animation1 = AnimationUtils.loadAnimation(this,
417 | R.anim.option_entry_from_bottom);
418 | mBottomView.startAnimation(animation1);
419 | mHandler.removeCallbacks(hideRunnable);
420 | mHandler.postDelayed(hideRunnable, HIDE_TIME);
421 | }
422 | }
423 |
424 | private class AnimationImp implements AnimationListener {
425 |
426 | @Override
427 | public void onAnimationEnd(Animation animation) {
428 |
429 | }
430 |
431 | @Override
432 | public void onAnimationRepeat(Animation animation) {
433 | }
434 |
435 | @Override
436 | public void onAnimationStart(Animation animation) {
437 | }
438 |
439 | }
440 |
441 | }
442 |
--------------------------------------------------------------------------------
/src/com/jit/video/VolumnController.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import android.content.Context;
4 | import android.view.Gravity;
5 | import android.view.LayoutInflater;
6 | import android.view.View;
7 | import android.widget.Toast;
8 |
9 | public class VolumnController {
10 | private Toast t;
11 | private VolumnView tv;
12 |
13 | private Context context;
14 |
15 | public VolumnController(Context context) {
16 | this.context = context;
17 | }
18 |
19 | public void show(float progress) {
20 | if (t == null) {
21 | t = new Toast(context);
22 | View layout = LayoutInflater.from(context).inflate(R.layout.vv, null);
23 | tv = (VolumnView) layout.findViewById(R.id.volumnView);
24 | t.setView(layout);
25 | t.setGravity(Gravity.BOTTOM, 0, 100);
26 | t.setDuration(Toast.LENGTH_SHORT);
27 | }
28 | tv.setProgress(progress);
29 | t.show();
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/com/jit/video/VolumnView.java:
--------------------------------------------------------------------------------
1 | package com.jit.video;
2 |
3 | import android.content.Context;
4 | import android.graphics.Bitmap;
5 | import android.graphics.BitmapFactory;
6 | import android.graphics.Canvas;
7 | import android.graphics.Color;
8 | import android.graphics.Paint;
9 | import android.graphics.Paint.Style;
10 | import android.graphics.RectF;
11 | import android.util.AttributeSet;
12 | import android.view.View;
13 |
14 | /**
15 | * 仿小米声音调节环形进度条
16 | */
17 | public class VolumnView extends View {
18 |
19 | // 半径
20 | float r1 = 0;
21 | float r2 = 0;
22 | float r3 = 0;
23 | // 外圆宽度
24 | float w1 = 15;
25 | // 内圆宽度
26 | float w2 = 30;
27 | Paint paint;
28 |
29 | // 进度
30 | float progress = 0;
31 |
32 | Bitmap bitmap;
33 |
34 | RectF oval;
35 |
36 | public VolumnView(Context context, AttributeSet attrs, int defStyle) {
37 | super(context, attrs, defStyle);
38 | init(context);
39 | }
40 |
41 | public VolumnView(Context context, AttributeSet attrs) {
42 | super(context, attrs);
43 | init(context);
44 | }
45 |
46 | public VolumnView(Context context) {
47 | super(context);
48 | init(context);
49 | }
50 |
51 | void init(Context context) {
52 | paint = new Paint(Paint.ANTI_ALIAS_FLAG);
53 | paint.setStyle(Style.STROKE);
54 | bitmap = BitmapFactory.decodeResource(getResources(), R.drawable.ling);
55 | }
56 |
57 | @Override
58 | protected void onDraw(Canvas canvas) {
59 | float cx = getMeasuredWidth() / 2;
60 | float cy = getMeasuredHeight() / 2;
61 | r1 = cx - w1 / 2;
62 | r2 = cx - w1 / 2 - w2 / 2;
63 | r3 = cx - w1 / 2 - w2;
64 |
65 | // 绘制外圆
66 | paint.setStrokeWidth(w1);
67 | paint.setColor(Color.parseColor("#454547"));
68 | canvas.drawCircle(cx, cy, r1, paint);
69 |
70 | // 绘制中间圆环
71 | paint.setColor(Color.parseColor("#747476"));
72 | paint.setStrokeWidth(w2);
73 | canvas.drawCircle(cx, cy, r2, paint);
74 |
75 | // 绘制内圆
76 | paint.setColor(Color.parseColor("#464648"));
77 | paint.setStyle(Style.FILL);
78 | canvas.drawCircle(cx, cy, r3, paint);
79 |
80 | // 绘制中间的图片
81 | canvas.drawBitmap(bitmap, cx - bitmap.getWidth() / 2,
82 | cx - bitmap.getHeight() / 2, paint);
83 |
84 | // 绘制文本
85 | paint.setColor(Color.WHITE);
86 | paint.setStrokeWidth(0);
87 | paint.setTextSize(40);
88 | float textWidth = paint.measureText("铃声"); // 测量字体宽度,我们需要根据字体的宽度设置在圆环中间
89 |
90 | canvas.drawText("铃声", cx - textWidth / 2, cx + bitmap.getHeight() / 2
91 | + 40, paint);
92 |
93 | // 绘制进度
94 | paint.setStyle(Style.STROKE);
95 | paint.setStrokeWidth(w2);
96 | paint.setColor(Color.WHITE);
97 | if (oval == null) {
98 | oval = new RectF(cx - r2, cy - r2, cx + r2, cy + r2); // 用于定义的圆弧的形状和大小的界限
99 | }
100 | canvas.drawArc(oval, 270, 360 * progress / 100, false, paint);
101 |
102 | super.onDraw(canvas);
103 | }
104 |
105 | /**
106 | * 设置进度
107 | *
108 | * @param progress
109 | * 范围(0-100)
110 | */
111 | public void setProgress(float progress) {
112 | this.progress = progress;
113 | if (this.progress >= 100)
114 | this.progress = 100;
115 | if (this.progress <= 0)
116 | this.progress = 0;
117 | postInvalidate();
118 | }
119 | }
120 |
--------------------------------------------------------------------------------