上一节对欢迎模块进行了综述(可参见 8. 统计模块 进行了解), 接下来将从视频模块开始详细介绍:
视频模块 (一) 之视频列表
视频模块 (二) 之视频详情 1
[视频模块 (二) 之视频详情 2]
知识点
显示视频简介, 视频目录, 视频播放等信息
使用第三方 CC 视频播放器播放
视频详情 1
任务综述:
"视频详情" 界面主要显示视频简介, 视频目录, 视频播放等信息, 由于该界面的数据是从 "视频列表" 界面传递过来的, 因此只需要把传递过来的数据展示到界面即可."视频详情" 界面中的视频使用第三方 CC 视频播放器播放.
7. "视频详情" 界面
任务分析:
点击视频列表的条目会跳转到 "视频详情" 界面, 该界面主要显示视频简介, 视频目录以及视频播放等信息, 界面效果如图所示.
"视频详情" 界面 1
"视频详情" 界面 2
任务实施:
(1)创建 "视频详情" 界面. 在 activity 包中创建 VideoDetailActivity, 布局文件名为 activity_video_detail.
(2)导入界面图片(13 个).
(3)添加 design 库. 由于 "视频详情" 界面用到了 design 库中的 TabLayout 类, 因此需要在该项目中添加 design 库. 在 AS 中, 选中项目, 右击选择 Open Module Settings/Dependencies/+/Library dependency/com.Android.support:design:25.3.1 库加入主项目.
(4)放置界面控件.
activity_video_detail.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- xmlns:App="http://schemas.android.com/apk/res-auto"
- Android:layout_width="fill_parent"
- Android:layout_height="fill_parent"
- Android:orientation="vertical">
- <RelativeLayout
- Android:id="@+id/rl_play"
- Android:layout_width="fill_parent"
- Android:layout_height="0dp"
- Android:layout_weight="2"
- Android:background="#000000">
- <SurfaceView
- Android:id="@+id/playerSurfaceView"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_centerInParent="true"/>
- <ProgressBar
- Android:id="@+id/bufferProgressBar"
- style="?android:attr/progressBarStyleLarge"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_centerInParent="true" />
- <ImageView
- Android:id="@+id/iv_center_play"
- Android:layout_width="60dp"
- Android:layout_height="60dp"
- Android:layout_centerInParent="true"
- Android:src="@drawable/big_stop_ic"
- Android:visibility="gone" />
- <LinearLayout
- Android:id="@+id/playerTopLayout"
- Android:layout_width="fill_parent"
- Android:layout_height="45dp"
- Android:layout_alignParentTop="true"
- Android:layout_gravity="top"
- Android:background="@drawable/play_top_bg"
- Android:orientation="horizontal"
- Android:padding="3dp"
- Android:visibility="gone">
- <ImageView
- Android:id="@+id/backPlayList"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:src="@drawable/back" />
- <TextView
- Android:id="@+id/videoIdText"
- Android:layout_width="0dp"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:layout_weight="1"
- Android:gravity="left"
- Android:singleLine="true"
- Android:textColor="#FFFFFFFF"
- Android:textSize="16sp" />
- <ImageView
- Android:id="@+id/iv_top_menu"
- Android:layout_width="45dp"
- Android:layout_height="45dp"
- Android:layout_gravity="center_vertical"
- Android:layout_marginLeft="15dp"
- Android:layout_marginRight="20dp"
- Android:padding="5dp"
- Android:scaleType="fitXY"
- Android:src="@drawable/more_ic" />
- </LinearLayout>
- <LinearLayout
- Android:id="@+id/playerBottomLayout"
- Android:layout_width="fill_parent"
- Android:layout_height="50dp"
- Android:layout_alignParentBottom="true"
- Android:background="#B2000000"
- Android:orientation="horizontal"
- Android:visibility="gone">
- <LinearLayout
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:gravity="center"
- Android:orientation="horizontal">
- <ImageView
- Android:id="@+id/iv_video_back"
- Android:layout_width="30dp"
- Android:layout_height="wrap_content"
- Android:layout_marginRight="5dp"
- Android:src="@drawable/up_ic" />
- <ImageView
- Android:id="@+id/iv_play"
- Android:layout_width="30dp"
- Android:layout_height="wrap_content"
- Android:src="@drawable/smallstop_ic" />
- <ImageView
- Android:id="@+id/iv_video_next"
- Android:layout_width="30dp"
- Android:layout_height="wrap_content"
- Android:layout_marginLeft="5dp"
- Android:src="@drawable/down_ic" />
- </LinearLayout>
- <TextView
- Android:id="@+id/playDuration"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:layout_marginLeft="5dp"
- Android:textColor="#FFFFFF" />
- <SeekBar
- Android:id="@+id/skbProgress"
- Android:layout_width="0dp"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:layout_marginLeft="10dp"
- Android:layout_weight="1"
- Android:maxHeight="3dp"
- Android:minHeight="3dp"
- Android:progressDrawable="@drawable/seekbar_style"/>
- <TextView
- Android:id="@+id/videoDuration"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:layout_marginRight="8dp"
- Android:textColor="#FFFFFF" />
- <ImageView
- Android:id="@+id/iv_fullscreen"
- Android:layout_width="40dp"
- Android:layout_height="40dp"
- Android:layout_gravity="center_vertical"
- Android:scaleType="centerInside"
- Android:src="@drawable/fullscreen_close" />
- <LinearLayout
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:gravity="center"
- Android:orientation="horizontal">
- <!-- 倍速播放选择 -->
- <TextView
- Android:id="@+id/tv_speed_play"
- style="@style/playBottomTextViewStyle"
- Android:text="@string/speed" />
- <TextView
- Android:id="@+id/tv_definition"
- style="@style/playBottomTextViewStyle"
- Android:text="@string/definition" />
- </LinearLayout>
- </LinearLayout>
- <LinearLayout
- Android:id="@+id/volumeLayout"
- Android:layout_width="30dp"
- Android:layout_height="wrap_content"
- Android:layout_alignParentRight="true"
- Android:layout_centerVertical="true"
- Android:layout_marginRight="30dp"
- Android:background="#80000000"
- Android:gravity="center_horizontal"
- Android:orientation="vertical"
- Android:visibility="gone">
- <com.itheima.topline.view.VerticalSeekBar
- Android:id="@+id/volumeSeekBar"
- Android:layout_width="wrap_content"
- Android:layout_height="200dp"
- Android:maxHeight="5dp"
- Android:minHeight="5dp"
- Android:progressDrawable="@drawable/seekbar_style" />
- <ImageView
- Android:layout_width="20dp"
- Android:layout_height="20dp"
- Android:layout_marginBottom="10dp"
- Android:src="@drawable/volume" />
- </LinearLayout>
- <ImageView
- Android:id="@+id/iv_lock"
- Android:layout_width="50dp"
- Android:layout_height="50dp"
- Android:layout_centerVertical="true"
- Android:layout_marginLeft="10dp"
- Android:padding="5dp"
- Android:scaleType="fitCenter"
- Android:src="@drawable/player_lock_bg"
- Android:visibility="gone" />
- </RelativeLayout>
- <LinearLayout
- Android:id="@+id/ll_below_info"
- Android:layout_width="fill_parent"
- Android:layout_height="0dp"
- Android:layout_weight="3"
- Android:orientation="vertical">
- <Android.support.design.widget.TabLayout
- Android:id="@+id/tabs"
- Android:layout_width="match_parent"
- Android:layout_height="wrap_content"
- Android:layout_marginLeft="8dp"
- Android:layout_marginRight="8dp"
- App:tabIndicatorColor="@android:color/holo_red_dark"
- App:tabSelectedTextColor="@android:color/holo_red_dark"
- App:tabTextColor="@android:color/black" />
- <!-- 可滑动的布局内容 -->
- <Android.support.v4.view.ViewPager
- Android:id="@+id/vp_view"
- Android:layout_width="match_parent"
- Android:layout_height="wrap_content" />
- </LinearLayout>
- </LinearLayout>
(5)创建 play_top_bg.xml 文件."视频详情" 界面需要一个渐变背景.
play_top_bg.xml
- <?xml version="1.0" encoding="utf-8"?>
- <shape xmlns:Android="http://schemas.android.com/apk/res/android">
- <gradient Android:startColor="#CC000000" Android:endColor="#00000000"
- Android:angle="270"/>
- </shape>
上述代码中, 用于定义形状, gradient 用于定义该形状为渐变色填充, startColor 为起始颜色, endColor 为结束颜色, angle 表示渐变角度, 且必须是 45 的整数倍.
(6)修改 strings.xml 文件.
- <string name="definition">清晰度</string>
- <string name="speed">倍速</string>
(7)创建播放条 SeekBar 的样式. 由于播放视频时的播放条具有一定的样式, 因此需要 res/drawable 文件夹中创建一个 seekbar_style.xml 文件, 用于设置播放条的样式.
seekbar_style.xml
- <layer-list xmlns:Android="http://schemas.android.com/apk/res/android">
- <item Android:id="@android:id/background">
- <shape>
- <corners Android:radius="10dip" />
- <gradient
- Android:angle="270"
- Android:centerColor="#151515"
- Android:centerY="0.45"
- Android:endColor="#151515"
- Android:startColor="#151515" />
- </shape>
- </item>
- <item Android:id="@android:id/secondaryProgress">
- <clip>
- <shape>
- <corners Android:radius="10dip" />
- <gradient
- Android:angle="270"
- Android:centerColor="#333333"
- Android:centerY="0.45"
- Android:endColor="#333333"
- Android:startColor="#333333" />
- </shape>
- </clip>
- </item>
- <item Android:id="@android:id/progress">
- <clip>
- <shape>
- <corners Android:radius="10dip" />
- <gradient
- Android:angle="270"
- Android:centerColor="#a07e5d"
- Android:centerY="0.45"
- Android:endColor="#a07e5d"
- Android:startColor="#a07e5d" />
- </shape>
- </clip>
- </item>
- </layer-list>
(8)创建清晰度播放选择的文本样式. 由于在横屏播放视频时有选择清晰度的文本, 这些文本都使用相同的样式, 因此需要在 res/values 文件夹的 styles.xml 文件中添加名为 playBottomTextStyle 的样式.
- <style name="playBottomTextViewStyle" parent="android:Widget.Holo.Light.TextView">
- <item name="android:layout_marginRight">5dp</item>
- <item name="android:textColor">#FFFFFF</item>
- <item name="android:textSize">13sp</item>
- <item name="android:visibility">gone</item>
- <item name="android:padding">5dp</item>
- <item name="android:layout_width">wrap_content</item>
- <item name="android:layout_height">wrap_content</item>
- <item name="android:layout_gravity">center_vertical</item>
- </style>
(9)创建视频的锁屏图标. 由于在横屏播放时有锁屏图标, 当点击锁屏时, 会显示一个上锁的图标(lock_ic.PNG), 当再次点击开锁时, 会显示一个开锁的图标(unlock_ic.PNG), 因此为了实现这个效果, 需要在 res/drawable 文件夹中创建一个 player_lock_bg.xml 文件.
player_lock_bg.xml
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:Android="http://schemas.android.com/apk/res/android">
- <item Android:drawable="@drawable/lock_ic" Android:state_selected="true" />
- <item Android:drawable="@drawable/unlock_ic" Android:state_selected="false" />
- </selector>
(10)创建视频简介布局和视频目录布局. 由于 "视频详情" 界面还包含一个视频简介与一个视频目录, 因此需要在 res/layout 文件夹中创建 video_detail_viewpager1.xml 文件与 video_detail_viewpager2.xml 文件, 分别用于显示视频简介布局与视频目录布局.
video_detail_viewpager1.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent">
- <TextView
- Android:id="@+id/tv_intro"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:layout_marginTop="8dp"
- Android:lineSpacingExtra="4dp"
- Android:paddingLeft="8dp"
- Android:paddingRight="8dp" />
- </LinearLayout>
video_detail_viewpager2.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:orientation="vertical">
- <View
- Android:layout_width="fill_parent"
- Android:layout_height="1dp"
- Android:background="#e1e1e1" />
- <ListView
- Android:id="@+id/lv_list"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent" />
- </LinearLayout>
8. "视频目录" 列表 Item
任务分析:
由于 "视频详情" 界面的视频目录用到了 Listview 控件, 因此需要为该控件创建一个 Item 布局, 界面效果如图所示.
"视频目录" 列表的 Item
任务实施:
(1)创建 "视频目录" 列表 Item:video_detail_item.xml.
(2)导入界面图片(2 个).
(3)放置界面控件.
一个 TextView 控件用于显示视频名称;
一个 ImageView 控件用于显示播放图标.
video_detail_item.xml
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:padding="10dp">
- <TextView
- Android:id="@+id/tv_video_name"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_alignParentLeft="true"
- Android:layout_centerVertical="true" />
- <ImageView
- Android:id="@+id/iv_icon"
- Android:layout_width="25dp"
- Android:layout_height="25dp"
- Android:layout_alignParentRight="true"
- Android:layout_centerVertical="true"
- Android:scaleType="fitXY"
- Android:src="@drawable/iv_video_icon" />
- </RelativeLayout>
9. 画面尺寸菜单
任务分析:
在 "视频详情" 界面点击正在播放的视频右下角的 "全屏" 图标, 界面会变成横屏显示, 当点击 "视频" 界面右上角的 "更多" 按钮时, 会弹出画面尺寸选择的菜单.
任务实施:
(1)创建 "画面尺寸菜单" 画面: play_top_menu.xml.
(2)放置界面控件.
一个 TextView 控件用于显示 "画面尺寸" 文字;
4 个 RadioButton 控件分别用于显示满屏, 100%,75%, 以及 50% 四个按钮.
play_top_menu.xml
- <?xml version="1.0" encoding="utf-8"?>
- <LinearLayout xmlns:Android="http://schemas.android.com/apk/res/android"
- Android:layout_width="match_parent"
- Android:layout_height="match_parent"
- Android:orientation="vertical"
- Android:paddingLeft="15dp"
- Android:paddingTop="5dp">
- <TextView
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_gravity="center_vertical"
- Android:layout_marginLeft="5dp"
- Android:layout_marginTop="15dp"
- Android:text="画面尺寸:"
- Android:textColor="#FFFFFF"
- Android:textSize="14sp" />
- <RadioGroup
- Android:id="@+id/rg_screensize"
- Android:layout_width="wrap_content"
- Android:layout_height="wrap_content"
- Android:layout_margin="5dp"
- Android:orientation="horizontal">
- <RadioButton
- Android:id="@+id/rb_screensize_full"
- style="@style/rbStyle"
- Android:text="满屏" />
- <RadioButton
- Android:id="@+id/rb_screensize_100"
- style="@style/rbStyle"
- Android:layout_marginLeft="10dp"
- Android:checked="true"
- Android:text="100%" />
- <RadioButton
- Android:id="@+id/rb_screensize_75"
- style="@style/rbStyle"
- Android:layout_marginLeft="10dp"
- Android:text="75%" />
- <RadioButton
- Android:id="@+id/rb_screensize_50"
- style="@style/rbStyle"
- Android:layout_marginLeft="10dp"
- Android:text="50%" />
- </RadioGroup>
- </LinearLayout>
(3)修改 styles.xml 文件. 由于在画 "面尺寸菜单" 界面中的满屏, 100%,75% 以及 50% 这 4 个按钮的样式是相同的, 因此需要在 res/values 文件夹的 styles.xml 文件中添加一个名为 rbStyle 的样式.
- <style name="rbStyle">
- <item name="android:button">@null</item>
- <item name="android:padding">5dp</item>
- <item name="android:textColor">@drawable/play_rb_textcolor</item>
- <item name="android:textSize">12sp</item>
- </style>
(4)创建 play_rb_textcolor.xml 文件. 由于画 "面尺寸菜单" 界面中的 4 个按钮在点击后字体颜色会发生变化, 以 "满屏" 按钮为例, 当未点击 "满屏" 按钮时, 按钮上的文字为白色; 当点击 "满屏" 按钮时, 按钮上的文字为橙色, 因此需要在 res/drawable 文件夹中创建一个 play_rb_textcolor.xml 文件(文字颜色选择器).
play_rb_textcolor.xml
- <?xml version="1.0" encoding="utf-8"?>
- <selector xmlns:Android="http://schemas.android.com/apk/res/android">
- <item Android:state_checked="true" Android:color="@color/rb_text_check" />
- <item Android:color="@android:color/white" Android:state_checked="false" />
- </selector>
(5)修改 colors.xml 文件. play_rb_textcolor.xml 文件用到了 rb_text_check 颜色值.
<color name="rb_text_check">#ff5200</color>
10. "视频目录" 列表 Adapter
任务分析:
"视频目录" 列表是通过 ListView 控件展示视频目录信息, 因此需要创建一个数据适配器 VideoDetailListAdapter 对 ListView 控件进行数据适配.
任务实施:
(1)创建 VideoDetailListAdapter 类. 在 adapter 包中创建一个 VideoDetailListAdapter 类继承 BaseAdapter 类, 并重写 getCount(),getItem(),getItemId(),getView()方法. 在 getView()方法中设置 xml 布局, 数据以及界面跳转方法, 同时, 为了减少缓存, 需要复用 convertView 对象.
VideoDetailListAdapter.java
- public class VideoDetailListAdapter extends BaseAdapter {
- private Context mContext;
- private List<VideoDetailBean> vdbl;
- private int selectedPosition = -1;// 点击时选中的位置
- private OnSelectListener onSelectListener;
- public VideoDetailListAdapter(Context context, OnSelectListener onSelectListener) {
- this.mContext = context;
- this.onSelectListener = onSelectListener;
- }
- public void setSelectedPosition(int position) {
- selectedPosition = position;
- }
- /**
- * 设置数据 更新界面
- */
- public void setData(List<VideoDetailBean> vdbl) {
- this.vdbl = vdbl;
- notifyDataSetChanged();
- }
- /**
- * 获取 Item 的总数
- */
- @Override
- public int getCount() {
- return vdbl == null ? 0 : vdbl.size();
- }
- /**
- * 根据 position 得到对应 Item 的对象
- */
- @Override
- public VideoDetailBean getItem(int position) {
- return vdbl == null ? null : vdbl.get(position);
- }
- /**
- * 根据 position 得到对应 Item 的 id
- */
- @Override
- public long getItemId(int position) {
- return position;
- }
- /**
- * 得到相应 position 对应的 Item 视图, 参数 position 是当前 Item 的位置,
- * 参数 convertView 就是滑出屏幕的 Item 的 View
- */
- @Override
- public View getView(final int position, View convertView, ViewGroup parent) {
- final ViewHolder vh;
- // 复用 convertView
- if (convertView == null) {
- vh = new ViewHolder();
- convertView = LayoutInflater.from(mContext).inflate(
- R.layout.video_detail_item, null);
- vh.title = (TextView) convertView.findViewById(R.id.tv_video_name);
- vh.iv_icon = (ImageView) convertView.findViewById(R.id.iv_icon);
- convertView.setTag(vh);
- } else {
- vh = (ViewHolder) convertView.getTag();
- }
- // 获取 position 对应的 Item 的数据对象
- final VideoDetailBean bean = getItem(position);
- vh.title.setTextColor(mContext.getResources().getColor(R.color.
- video_detail_text_color));
- if (bean != null) {
- vh.title.setText(bean.getVideo_name());
- // 设置选中效果
- if (selectedPosition == position) {
- vh.iv_icon.setImageResource(R.drawable.iv_video_selected_icon);
- vh.title.setTextColor(mContext.getResources().getColor(R.color.
- rdTextColorPress));
- } else {
- vh.iv_icon.setImageResource(R.drawable.iv_video_icon);
- vh.title.setTextColor(mContext.getResources().getColor(R.color.
- video_detail_text_color));
- }
- }
- // 每个 Item 的点击事件
- convertView.setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View v) {
- // 跳转到习题详情界面
- if (bean == null) {
- return;
- }
- // 播放视频
- onSelectListener.onSelect(position, vh.iv_icon);
- }
- });
- return convertView;
- }
- class ViewHolder {
- public TextView title;
- public ImageView iv_icon;
- }
- /**
- * 创建 OnSelectListener 接口把位置 position 和控件 ImageView 传递到 Activity 界面
- */
- public interface OnSelectListener {
- void onSelect(int position, ImageView iv);
- }
- }
(2)修改 colors.xml 文件. 由于视频目录标题多次使用同一颜色值, 因此为了减少代码量与方便调用, 需要把视频目录文本的颜色值添加到 res/values 文件夹中的 colors.xml 文件中.
<color name="video_detail_text_color">#333333</color>
11. 创建 NewsDemoApplication
任务分析:
由于 "视频播放" 界面用到了第三方 CC 视频播放器, 同时在播放视频之前需要启动服务, 因此在该项目中需要创建一个 Application 用于处理 CC 视频播放器用到的服务.
任务实施:
(1)添加 CCSDK.jar 库. 由于视频播放调用是第三方 CC 视频播放器, 因此需要在 Project 选项卡下将 CCSDK.jar 复制到 App 中的 libs 文件夹, 选择 CCSDK.jar 库 / 右击选择 Add As Library 选项 / 弹出一个对话框 / 把该 jar 包放在 App 项目中即可.
(2)创建 NewsDemoApplication.java 文件. 由于 CC 视频播放器在播放视频时需要开启 DRMServer 服务. 因此需要在 com.XXXX.newsdemo 文件夹中创建一个 NewsDemoApplication 类, 用于设置视频播放时用到的服务.
NewsDemoApplication.java
- public class NewsDemoApplication extends Application {
- private DRMServer drmServer;// 视频播放时用到的服务
- @Override
- public void onCreate() {
- startDRMServer();
- super.onCreate();
- }
- // 启动 DRMServer
- public void startDRMServer() {
- if (drmServer == null) {
- drmServer = new DRMServer();
- drmServer.setRequestRetryCount(10);
- }
- try {
- drmServer.start();
- setDrmServerPort(drmServer.getPort());
- } catch (Exception e) {
- Toast.makeText(getApplicationContext(), "启动解密服务失败, 请检查网络限制情况",
- Toast.LENGTH_LONG).show();
- }
- }
- @Override
- public void onTerminate() {
- if (drmServer != null) {
- drmServer.stop();
- }
- super.onTerminate();
- }
- private int drmServerPort;
- public int getDrmServerPort() {
- return drmServerPort;
- }
- public void setDrmServerPort(int drmServerPort) {
- this.drmServerPort = drmServerPort;
- }
- public DRMServer getDRMServer() {
- return drmServer;
- }
- }
(3)修改清单文件. 在 AndroidManifest.xml 文件中需要设置 application 标签中的 name 属性值为 ".NewsDemoApplication".
12. 创建 VideoDetailPagerAdapter
任务分许:
由于 "视频详情" 界面用到了 ViewPager 控件, 因此需要创建一个 VideoDetailPagerAdapter 对 ViewPager 控件进行数据填充.
任务实施:
在 adapter 文件夹中创建一个 VideoDetailPagerAdapter 类并继承 PagerAdapter 类.
VideoDetailPagerAdapter.java
- public class VideoDetailPagerAdapter extends PagerAdapter {
- private List<View> mViewList;
- private List<String> mTitleList;
- public VideoDetailPagerAdapter(List<View> mViewList, List<String> mTitleList) {
- this.mViewList = mViewList;
- this.mTitleList=mTitleList;
- }
- @Override
- public int getCount() {
- return mViewList.size();// 页卡数
- }
- @Override
- public boolean isViewFromObject(View view, Object object) {
- return view == object;// 官方推荐写法
- }
- @Override
- public Object instantiateItem(ViewGroup container, int position) {
- container.addView(mViewList.get(position));// 添加页卡
- return mViewList.get(position);
- }
- @Override
- public void destroyItem(ViewGroup container, int position, Object object) {
- container.removeView(mViewList.get(position));// 删除页卡
- }
- @Override
- public CharSequence getPageTitle(int position) {
- return mTitleList.get(position);// 页卡标题
- }
- }
13. 创建 ParamsUtils
任务分析:
由于在 "视频详情" 界面中需要把时间转换成字符串显示到界面上, 并且还需要把 dp 转换成 px, 因此需要创建一个工具类, 并在该类中分别创建两个方法实现这些功能.
任务实施:
在 utils 包中创建一个 ParamsUtils 类, 在该类中创建 millsecondsToStr()方法与 dpToPx()方法, 分别用于把时间转换成字符串, 以及把 dp 转换成 px.
ParamsUtils.java
- public class ParamsUtils {
- public final static int INVALID = -1;
- public static int getInt(String str){
- int num = INVALID;
- try {
- num = Integer.parseInt(str);
- } catch (NumberFormatException e) {
- }
- return num;
- }
- public static String millsecondsToStr(int seconds){ // 把时间转换成字符串
- seconds = seconds / 1000;
- String result = "";
- int hour = 0, min = 0, second = 0;
- hour = seconds / 3600;
- min = (seconds - hour * 3600) / 60;
- second = seconds - hour * 3600 - min * 60;
- if (hour <10) {
- result += "0" + hour + ":";
- } else {
- result += hour + ":";
- }
- if (min < 10) {
- result += "0" + min + ":";
- } else {
- result += min + ":";
- }
- if (second < 10) {
- result += "0" + second;
- } else {
- result += second;
- }
- return result;
- }
- public static int dpToPx(Context context, int height){ //dp 转换成 px
- float density = context.getResources().getDisplayMetrics().density;
- height = (int) (height * density + 0.5f);
- return height;
- }
- }
14. 视频播放进度条
任务分析:
由于在 "视频详情" 界面播放视频时会显示视频播放的进度, 因此需要创建一个视频播放的进度条.
任务实施:
在 view 文件夹中创建一个 VerticalSeekBar 类用于设置视频播放时的进度条.
VerticalSeekBar.java
- public class VerticalSeekBar extends SeekBar {
- public VerticalSeekBar(Context context) {
- super(context);
- }
- public VerticalSeekBar(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- public VerticalSeekBar(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- protected void onSizeChanged(int w, int h, int oldw, int oldh) {
- super.onSizeChanged(h, w, oldh, oldw);
- }
- @Override
- protected synchronized void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
- super.onMeasure(heightMeasureSpec, widthMeasureSpec);
- setMeasuredDimension(getMeasuredHeight(), getMeasuredWidth());
- }
- protected void onDraw(Canvas c) {
- c.rotate(-90);
- c.translate(-getHeight(), 0);
- super.onDraw(c);
- }
- @Override
- public synchronized void setProgress(int progress) {
- super.setProgress(progress);
- onSizeChanged(getWidth(), getHeight(), 0, 0);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (!isEnabled()) {
- return false;
- }
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- case MotionEvent.ACTION_MOVE:
- case MotionEvent.ACTION_UP:
- setProgress((int) ((int) getMax() - (getMax() * event.getY() /
- getHeight())));
- break;
- default:
- return super.onTouchEvent(event);
- }
- return true;
- }
- }
15. 画面尺寸菜单逻辑代码
任务分析:
当横屏播放视频时, 点击屏蔽右上角的 "更多" 图标会弹出一个选择画面尺寸的菜单, 画面尺寸菜单中的选项有满屏, 100%,75% 以及 50%, 点击其中任意一项就会使播放界面缩小或放大.
任务实施:
(1)创建 PlayTopPopupWindow 类. 在 view 文件夹中创建一个 PlayTopPopupWindow 类, 在该类中创建一个 setScreenSizeCheckLister()方法, 用于监听 "选择画面尺寸" 界面中按钮的点击事件.
(2)设置画面尺寸菜单. 在 PlayTopPopupWindow 类中创建一个 showAsDropDown()方法, 用于设置画面尺寸菜单的显示.
PlayTopPopupWindow.java
- /**
- * 弹出菜单
- */
- public class PlayTopPopupWindow {
- private PopupWindow popupWindow;
- private RadioGroup rgScreenSize;
- public PlayTopPopupWindow(Context context, int height) {
- View view = LayoutInflater.from(context).inflate(R.layout.play_top_menu, null);
- rgScreenSize = findById(R.id.rg_screensize, view);
- popupWindow = new PopupWindow(view, height * 2 / 3, height);
- popupWindow.setBackgroundDrawable(new ColorDrawable(Color.argb(178, 0, 0, 0)));
- }
- public void setScreenSizeCheckLister(RadioGroup.OnCheckedChangeListener listener) {
- rgScreenSize.setOnCheckedChangeListener(listener);
- }
- public void showAsDropDown(View parent) {
- popupWindow.showAtLocation(parent, Gravity.RIGHT, 0, 0);
- popupWindow.setFocusable(true);
- popupWindow.setOutsideTouchable(true);
- popupWindow.update();
- }
- public void dismiss() {
- popupWindow.dismiss();
- }
- @SuppressWarnings("unchecked")
- private <T extends View> T findById(int resId, View view) {
- return (T) view.findViewById(resId);
- }
- }
来源: http://www.jianshu.com/p/9eb1a397183a