当前位置:首页 > 人工智能

DistributedVideoPlayer 分布式视频播放器(一)

想了解更多内容,分布放器请访问:

和华为官方合作共建的式视鸿蒙技术社区

https://harmonyos.51cto.com

介绍

本示例是在官方Video Play Ability 模板基础上做了扩展开发,官方模板提供基本的视频播放功能,并允许您在手机和电视之间传输视频.

应用分为手机端(entry)和TV端(entrytv),频播以及一个依赖模块(commonlib).

在示例的基础之上,手机端增加了视频播放列表功能,以及播放详情页和评论功能;手机端播放的视频可以流转到TV端,并实现远端遥控的功能。

内容比较多,分布放器会分两期给大家讲解,本期文章主要讲解的内容是手机端部分:

1.实现一个视频播放器 2.实现一个播放列表 3.实现一个评论功能.

[本文正在参与优质创作者激励]

效果展示

搭建环境

安装DevEco Studio,详情请参考DevEco Studio下载。式视

设置DevEco Studio开发环境,频播DevEco Studio开发环境需要依赖于网络环境,分布放器需要连接上网络才能确保工具的式视正常使用,可以根据如下两种情况来配置开发环境:

如果可以直接访问Internet,频播只需进行下载HarmonyOS SDK操作。香港云服务器分布放器

如果网络不能直接访问Internet,式视需要通过代理服务器才可以访问,频播请参考配置开发环境。分布放器

下载源码后,式视使用DevEco 打开项目。频播

代码结构

Java代码

│  config.json │ ├─java │  └─com │      └─buty │          └─distributedvideoplayer │              │  MainAbility.java                │              │  MyApplication.java │              │ │              ├─ability │              │      DevicesSelectAbility.java    │              │      MainAbilitySlice.java           #视频播放列表页 │              │      SyncControlServiceAbility.java   │              │      VideoPlayAbility.java           #视频播放Ability │              │      VideoPlayAbilitySlice.java      #视频播放详情和评论页 │              │ │              ├─components │              │      EpisodesSelectionDialog.java     │              │      RemoteController.java │              │      VideoPlayerPlaybackButton.java  #播放按钮组件 │              │      VideoPlayerSlider.java          #播放时间进度条 │              │ │              ├─constant │              │      Constants.java                  #常量 │              │      ResolutionEnum.java             #分辨率枚举 │              │      RouteRegister.java              #自定义路由 │              │ │              ├─data │              │      VideoInfo.java                  #视频基础信息 │              │      VideoInfoService.java           #视频信息服务,用于模拟数据 │              │      Videos.java                     #视频列表 │              │  │              ├─model │              │      CommentModel.java               #评论模型 │              │      DeviceModel.java                 │              │      ResolutionModel.java            #解析度模型 │              │      VideoModel.java                 #视频模型 │              │ │              ├─provider │              │      CommentItemProvider.java        #评论数据提供程序 │              │      DeviceItemProvider.java       │              │      ResolutionItemProvider.java     #解析度数据提供程序 │              │      VideoItemProvider.java          #视频数据提供程序 │              │ │              └─utils │                      AppUtil.java                   #工具类 │                      DateUtils.java 

资源文件

└─resources     ├─base     │  ├─element     │  │      color.json     │  │      float.json     │  │      strarray.json     │  │      string.json     │  │     │  ├─graphic     │  │      background_ability_control_bg.xml               │  │      background_ability_control_middle.xml     │  │      background_ability_control_ok.xml     │  │      background_ability_devices.xml     │  │      background_ability_episodes.xml     │  │      background_button_click.xml     │  │      background_button_clicked.xml     │  │      background_episodes_item.xml     │  │      background_episodes_quality.xml     │  │      background_episodes_trailer.xml     │  │      background_slide_thumb.xml     │  │      background_switch_checked.xml     │  │      background_switch_empty.xml     │  │      background_switch_thumb.xml     │  │      background_switch_track.xml     │  │      list_divider.xml     │  │      shape_slider_thumb.xml     │  │     │  ├─layout     │  │      ability_main.xml                                #播放列表布局     │  │      comments_item.xml                               #单条评论布局     │  │      dialog_playlist.xml                          │  │      dialog_resolution_list.xml     │  │      dialog_table_layout.xml     │  │      hm_sample_ability_video_box.xml                 #视频播放组件页     │  │      hm_sample_ability_video_comments.xml            #播放详情布局页     │  │      hm_sample_view_video_box_seek_bar_style1.xml    #播放进度条布局     │  │      hm_sample_view_video_box_seek_bar_style2.xml     │  │      remote_ability_control.xml     │  │      remote_ability_episodes.xml     │  │      remote_ability_select_devices.xml     │  │      remote_ability_sound_equipment.xml     │  │      remote_device_item.xml     │  │      remote_episodes_item.xml     │  │      remote_video_quality_item.xml     │  │     │  ├─media     │  │      comments.png     │  │      great.png     │  │      icon.png     │  │      ic_anthology.png     │  │     │  └─profile     ├─en     │  └─element     │          string.json     │     ├─rawfile     │      videos.json                                      #模拟数据JSON文件     │     └─zh         └─element                 string.json 

实现步骤

1.实现一个视频播放器

引入对commonlib的依赖后,实现一个视频播放器就很容易了.

entry的build.gradle 增加对commonlib的依赖

dependencies {      implementation fileTree(dir: libs, include: [*.jar, *.har])     testImplementation junit:junit:4.13     ohosTestImplementation com.huawei.ohos.testkit:runner:1.0.0.200     //引用commonlib 依赖     implementation project(path: :commonlib) } 

1.1.页面布局 hm_sample_ability_video_comments.xml

添加一个VideoPlayerView组件

<?xml version="1.0" encoding="utf-8"?> <StackLayout     xmlns:ohos="http://schemas.huawei.com/res/ohos"     ohos:id="$+id:root_layout"     ohos:height="match_parent"     ohos:width="match_parent"     ohos:background_element="#FFFFFFFF"     ohos:orientation="vertical">      <com.buty.distributedvideoplayer.player.ui.widget.media.VideoPlayerView         ohos:id="$+id:video_view"         ohos:height="250vp"         ohos:width="match_parent"/> ... </StackLayout> 

1.2.Java代码

获取视频组件对象后,只需要2步就可以了: 1.设置视频资源路径和描述; 2.设置播放器核心组件和自定义组件.几行关键代码 VideoPlayAbilitySlice.java

/**  * 初始化播放器  */ private void initPlayer() {      HiLog.debug(LABEL, "initPlayer");     //自定义视频播放视图组件     player = (VideoPlayerView) findComponentById(ResourceTable.Id_video_view);      if (player != null) {          //获取视频信息服务         videoService = new VideoInfoService(getContext());         //获取当前播放视频的路径         String path = videoService                 .getVideoInfoByIndex(currentPlayingIndex)                 .getResolutions()                 .get(currentPlayingResolutionIndex)                 .getUrl();         //视频描述         String videoDesc = videoService.getVideoInfoByIndex(currentPlayingIndex).getVideoDesc();         HiLog.debug(LABEL, "videoDesc = " + videoDesc + " path = " + path);          if (path != null) {              //设置路径和描述             player.setVideoPathAndTitle(path, videoDesc);             //视频准备完毕就播放并设置播放进度条             player.setPlayerOnPreparedListener(                     () -> {                          player.start();                         //设置播放位置                         player.seekTo(currentPlayingPosition);                     });             //双击播放或暂停             player.setDoubleClickedListener(                     component -> {                          //是否在控制TV端                         if (remoteController != null && remoteController.isShown()) {                              return;                         }                         HiLog.debug(LABEL, "VideoPlayView double-click event");                         if (player.isPlaying()) {                              player.pause();                         } else {                              player.start();                         }                     });             //监听播放错误             player.setErrorListener(                     (errorType, errorCode) -> {                          ToastDialog toast = new ToastDialog(getContext());                         switch (errorType) {                              case HmPlayerAdapter.ERROR_LOADING_RESOURCE:                                 toast.setText(                                         AppUtil.getStringResource(                                                 getContext(), ResourceTable.String_media_file_loading_error));                                 break;                             case HmPlayerAdapter.ERROR_INVALID_OPERATION:                                 toast.setText(                                         AppUtil.getStringResource(                                                 getContext(), ResourceTable.String_invalid_operation));                                 break;                             default:                                 toast.setText(                                         AppUtil.getStringResource(                                                 getContext(), ResourceTable.String_undefined_error_type));                                 break;                         }                         getUITaskDispatcher().asyncDispatch(toast::show);                     });         }         //添加核心组件,播放时间进度滑块         addCoreComponent();         //添加自定义组件         addCustomComponent();         HiLog.debug(LABEL, "initPlayer finish");     } } 

2.实现一个视频播放列表功能

2.1.页面布局 ability_main.xml

使用了DirectionalLayout布局组件,还有ScrollView和ListContainer组件

<?xml version="1.0" encoding="utf-8"?> <DirectionalLayout     xmlns:ohos="http://schemas.huawei.com/res/ohos"     ohos:id="$+id:ability_main_root"     ohos:height="match_parent"     ohos:width="match_parent"     ohos:orientation="vertical">      <DirectionalLayout         ohos:id="$+id:ability_main_titlebar"         ohos:height="match_content"         ohos:width="match_parent"         ohos:background_element="#B0B0B0"         ohos:orientation="horizontal"         ohos:padding="10vp">          <DirectionalLayout             ohos:height="match_parent"             ohos:width="match_content"             ohos:weight="1">              <Text                 ohos:id="$+id:tag_favorite"                 ohos:height="match_content"                 ohos:width="match_parent"                 ohos:text="关注"                 ohos:text_size="$float:normal_text_size_15"                 />         </DirectionalLayout>          <DirectionalLayout             ohos:height="match_content"             ohos:width="match_content"             ohos:weight="1">              <Text                 ohos:id="$+id:tag_support"                 ohos:height="match_content"                 ohos:width="match_content"                 ohos:text="推荐"                 ohos:text_size="$float:normal_text_size_15"                 />         </DirectionalLayout>          <DirectionalLayout             ohos:height="match_content"             ohos:width="match_content"             ohos:weight="1">              <Text                 ohos:id="$+id:tag_movie"                 ohos:height="match_content"                 ohos:width="match_content"                 ohos:element_end="$id:favorite"                 ohos:text="电影"                 ohos:text_color="#1C6AE9"                 ohos:text_size="$float:normal_text_size_15"                 ohos:text_weight="600"/>              <Component                 ohos:id="$+id:device_item_divider"                 ohos:height="2vp"                 ohos:width="30vp"                 ohos:background_element="$graphic:list_divider"/>         </DirectionalLayout>          <DirectionalLayout             ohos:height="match_content"             ohos:width="match_content"             ohos:weight="1">              <Text                 ohos:id="$+id:tag_live"                 ohos:height="match_content"                 ohos:width="match_parent"                 ohos:text="直播"                 ohos:text_size="$float:normal_text_size_15"                 />         </DirectionalLayout>          <DirectionalLayout             ohos:height="match_content"             ohos:width="match_content"             ohos:weight="1">              <Text                 ohos:id="$+id:tag_tv"                 ohos:height="match_content"                 ohos:width="match_parent"                 ohos:text="电视"                 ohos:text_size="$float:normal_text_size_15"                 />         </DirectionalLayout>      </DirectionalLayout>      <ScrollView         ohos:height="match_parent"         ohos:width="match_parent"         ohos:id="$+id:video_list_scroll" >          <ListContainer             ohos:id="$+id:videos_container"             ohos:height="match_parent"             ohos:width="match_parent">          </ListContainer>     </ScrollView> </DirectionalLayout> 

2.2.Java代码

申请用户敏感权限授权 MainAbility.java

/**  * Entry to the main interface of the program  */ public class MainAbility extends Ability {      private static final int REQUEST_CODE = 1;      //读写媒体权限     private final String[] permissionLists             = new String[]{ "ohos.permission.READ_MEDIA", "ohos.permission.WRITE_MEDIA"};      @Override     public void onStart(Intent intent) {          super.onStart(intent);         super.setUIContent(ResourceTable.Layout_ability_main);         super.setMainRoute(MainAbilitySlice.class.getName());          //申请授权         verifyPermissions();     }     private void verifyPermissions() {          for (String permissionList : permissionLists) {              int result = verifySelfPermission(permissionList);             if (result != IBundleManager.PERMISSION_GRANTED) {                  requestPermissionsFromUser(permissionLists, REQUEST_CODE);             }         }     } ... 

通过VideoInfoService读取videos.json文件初始化视频容器列表MainAbilitySlice.java

public class MainAbilitySlice extends AbilitySlice {      public static final HiLogLabel LABEL = new HiLogLabel(0, 0, "=>MainAbilitySlice");     private VideoInfoService videoService;      @Override     protected void onStart(Intent intent) {          super.onStart(intent);         //加载视频播放器页面         super.setUIContent(ResourceTable.Layout_ability_main);         initVideoContainer();      }      /**      * 模拟数据      * 初始化视频容器列表      */     private void initVideoContainer() {          HiLog.debug(LABEL, "initVideoContainer");         List<VideoModel> videos = new ArrayList<>();         //获取视频信息服务         videoService = new VideoInfoService(getContext());          for (int i = 0; i < 7; i++) {              VideoModel video = new VideoModel();             video.setComments(new Random().nextInt(1000));             video.setFavorites(new Random().nextInt(1000));             video.setGreats(new Random().nextInt(10000));             VideoInfo videoInfo = videoService.getVideoInfoByIndex(i);             videoInfo.setIndex(i);             video.setVideoInfo(videoInfo);             videos.add(video);         }          ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_videos_container);         //容器绑定数据提供程序         VideoItemProvider provider = new VideoItemProvider(this, videos, this);         listContainer.setItemProvider(provider);     } } 

 视频容器列表数据提供程序 VideoItemProvider.java

public class VideoItemProvider extends BaseItemProvider {      private static final HiLogLabel LABEL = new HiLogLabel(0, 0, "=>VideoItemProvider");     private final Context context;     private final List<VideoModel> list;     private AbilitySlice abilitySlice;     //当前播放视频分辨率索引     private int currentPlayingResolutionIndex = 0;      /**      * Initialization      */     public VideoItemProvider(Context context, List<VideoModel> list, AbilitySlice abilitySlice) {          HiLog.debug(LABEL, "VideoItemProvider");         this.context = context;         this.list = list;         this.abilitySlice = abilitySlice;     }      public Context getContext() {          return context;     }      @Override     public int getCount() {          return list == null ? 0 : list.size();     }      @Override     public Object getItem(int position) {          if (list != null && position >= 0 && position < list.size()) {              return list.get(position);         }         return new VideoModel();     }      @Override     public long getItemId(int position) {          return position;     }      @Override     public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {          HiLog.debug(LABEL, "getComponent:" + convertComponent + "," + componentContainer);         final Component cpt;         final VideoPlayerView player;          VideoModel item = list.get(position);          //初次获取组件         if (convertComponent == null) {              cpt = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_hm_sample_ability_video_box, componentContainer, false);             player = (VideoPlayerView) cpt.findComponentById(ResourceTable.Id_video_view);             //初始化播放器组件             initPlayer(player,item.getVideoInfo());         } else {              //ScrollView滑动时也会调用getComponent方法,             cpt = convertComponent;             player = (VideoPlayerView) cpt.findComponentById(ResourceTable.Id_video_view);         }          //设置其他组件的值         Text text_favorites = (Text) cpt.findComponentById(ResourceTable.Id_text_favorites);         Text text_comments = (Text) cpt.findComponentById(ResourceTable.Id_text_comments);         Text text_greats = (Text) cpt.findComponentById(ResourceTable.Id_text_greats);         //注意setText的参数类型是字符串         text_favorites.setText(item.getFavorites() + "");         text_comments.setText(item.getComments() + "");         text_greats.setText(item.getGreats() + "");         //点击评论图标,停止当前播放器,打开VideoPlayAbility的Slice页面         Image commentImage = (Image) cpt.findComponentById(ResourceTable.Id_image_comment);         commentImage.setClickedListener(component -> {              //停止播放,列表页面的播放器             player.stopPlayback();             //打开带有评论的播放页面             startVideoPlayDetail(item,player);         });         return cpt;     }      /**      * 初始化播放器      */     private void initPlayer(VideoPlayerView player, VideoInfo videoInfo) {          HiLog.debug(LABEL, "initPlayer");         if (player != null) {              //视频路径             String path = videoInfo                     .getResolutions()                     .get(currentPlayingResolutionIndex)                     .getUrl();             HiLog.debug(LABEL, "path:" + path);              //视频描述             String videoDesc = videoInfo.getVideoDesc();             HiLog.debug(LABEL, "videoDesc  = " + videoDesc + " path = " + path);              if(path!=null) {                  //设置路径和名称                 player.setVideoPathAndTitle(path, videoDesc);                 //双击播放或暂停                 player.setDoubleClickedListener(                         component -> {                              HiLog.debug(LABEL, "VideoPlayView double-click event");                             if (player.isPlaying()) {                                  player.pause();                             } else {                                  player.start();                             }                         });                 //监听播放错误                 player.setErrorListener(                         (errorType, errorCode) -> {                              ToastDialog toast = new ToastDialog(getContext());                             switch (errorType) {                                  case HmPlayerAdapter.ERROR_LOADING_RESOURCE:                                     toast.setText(                                             AppUtil.getStringResource(                                                     getContext(), ResourceTable.String_media_file_loading_error));                                     break;                                 case HmPlayerAdapter.ERROR_INVALID_OPERATION:                                     toast.setText(                                             AppUtil.getStringResource(                                                     getContext(), ResourceTable.String_invalid_operation));                                     break;                                 default:                                     toast.setText(                                             AppUtil.getStringResource(                                                     getContext(), ResourceTable.String_undefined_error_type));                                     break;                             }                             abilitySlice.getUITaskDispatcher().asyncDispatch(toast::show);                         });             }             //添加核心组件,播放时间进度滑块             addCoreComponent(player);             //添加自定义组件             HiLog.debug(LABEL, "initPlayer finish");         }     }      /**      * 添加播放按钮,剧集,站群服务器进度条等核心组件      * Adding core component like playback button and seek bar      */     private void addCoreComponent(VideoPlayerView player) {          HiLog.debug(LABEL, "addCoreComponent");         //添加播放按钮组件         player.addPlaybackButton(new VideoPlayerPlaybackButton(getContext()), VideoBoxArea.BOTTOM);         //添加播放进度条组件         player.addSeekBar(                 new VideoPlayerSlider(getContext()),                 VideoBoxArea.BOTTOM,                 (int) AppUtil.getFloatResource(getContext(), ResourceTable.Float_normal_margin_24));     }      /**      * 打开视频播放详情页      */     private void startVideoPlayDetail(VideoModel item,VideoPlayerView player) {          HiLog.debug(LABEL, "startVideoPlayDetail ");         //启动评论播放页面         Intent intentService = new Intent();         //播放视频评论数         intentService.setParam("comments",String.valueOf(item.getComments()));          VideoInfo videoInfo=item.getVideoInfo();          if(videoInfo!=null) {              //播放视频在播放列表中的索引             intentService.setParam("currentPlayingIndex", videoInfo.getIndex());             //播放视频的分辨率索引             intentService.setParam("currentPlayingResolutionIndex", currentPlayingResolutionIndex);             //当前视频播放的位置             intentService.setParam(RemoteConstant.INTENT_PARAM_REMOTE_START_POSITION,(int)player.getCurrentPosition());             HiLog.debug(LABEL,RemoteConstant.INTENT_PARAM_REMOTE_START_POSITION+":"+player.getCurrentPosition());         }         Operation operation =                 new Intent.OperationBuilder()                         .withDeviceId("")                         .withBundleName(abilitySlice.getBundleName())                         .withAbilityName(VideoPlayAbility.class)                         .build();         intentService.setOperation(operation);         abilitySlice.startAbility(intentService);     } } 

3.实现一个评论功能

3.1.页面布局,评论列表布局页 hm_sample_ability_video_comments.xml

使用了StackLayout,DependentLayout布局组件和ListContainer,TextField,Text 组件

...     <!-- 工具栏 -->     <DependentLayout         ohos:id="$+id:comments_bar"         ohos:height="40vp"         ohos:width="match_parent"         ohos:background_element="#FFDDDADA"         ohos:layout_alignment="top"         ohos:top_margin="250vp">          <DirectionalLayout             ohos:id="$+id:favorite"             ohos:height="match_parent"             ohos:width="match_content"             ohos:align_parent_left="true"             ohos:left_margin="10vp"             ohos:orientation="horizontal"             ohos:padding="4vp">              <Text                 ohos:id="$+id:text_favorites"                 ohos:height="match_parent"                 ohos:width="match_parent"                 ohos:left_padding="5vp"                 ohos:text="简介"                 ohos:text_size="16fp"                 ohos:text_weight="600">              </Text>         </DirectionalLayout>          <DirectionalLayout             ohos:id="$+id:comment"             ohos:height="match_parent"             ohos:width="match_content"             ohos:end_of="$id:favorite"             ohos:left_margin="20vp"             ohos:orientation="horizontal"             ohos:padding="4vp">              <Text                 ohos:id="$+id:text_comment"                 ohos:height="match_parent"                 ohos:width="match_content"                 ohos:left_padding="5vp"                 ohos:text="评论"                 ohos:text_weight="600"                 ohos:text_size="16fp">             </Text>              <Text                 ohos:id="$+id:text_comments"                 ohos:height="match_parent"                 ohos:width="match_content"                 ohos:left_padding="5vp"                 ohos:text="1161"                 ohos:text_weight="600"                 ohos:text_size="16fp">             </Text>         </DirectionalLayout>      </DependentLayout>      <!-- 评论列表 -->     <DependentLayout         ohos:id="$+id:comments_view"         ohos:height="match_parent"         ohos:width="match_parent"         ohos:background_element="#FFFDFFFF"         ohos:top_margin="290vp">          <ListContainer             ohos:id="$+id:comments_container"             ohos:height="match_parent"             ohos:width="match_parent"             ohos:layout_alignment="horizontal_center"             ohos:orientation="vertical"/>      </DependentLayout>      <!-- 评论对话框 -->     <DependentLayout         ohos:id="$+id:comments_dialog"         ohos:height="70vp"         ohos:width="match_parent"         ohos:background_element="#FFF4F4F8"         ohos:layout_alignment="bottom"         ohos:padding="5vp">          <TextField             ohos:id="$+id:comment_tf"             ohos:height="match_parent"             ohos:width="match_parent"             ohos:hint="发一条友好的评论吧"             ohos:right_padding="60vp"             ohos:text_size="16vp"></TextField>          <Text             ohos:id="$+id:sent_comment"             ohos:height="match_parent"             ohos:width="60vp"             ohos:align_parent_right="true"             ohos:background_element="#FF7ECCCF"             ohos:text="发送"             ohos:input_enter_key_type="enter_key_type_send"             ohos:text_alignment="center"             ohos:text_size="16vp">         </Text>     </DependentLayout> 

3.2.页面布局,单条评论组件布局 comments_item.xml

使用了DependentLayout,DirectionalLayout布局组件和Image,Component,Text 组件

<?xml version="1.0" encoding="utf-8"?> <DependentLayout     xmlns:ohos="http://schemas.huawei.com/res/ohos"     ohos:height="match_content"     ohos:width="match_parent">      <Image         ohos:id="$+id:header_item_icon"         ohos:height="50vp"         ohos:width="50vp"         ohos:end_margin="13vp"         ohos:left_margin="5vp"         ohos:image_src="$media:ic_header"         ohos:scale_mode="stretch"         ohos:top_margin="13vp"/>      <DirectionalLayout         ohos:id="$+id:comment_item_content"         ohos:height="match_content"         ohos:width="250vp"         ohos:bottom_padding="5vp"         ohos:orientation="vertical"         ohos:right_of="$id:header_item_icon">          <Text             ohos:id="$+id:comment_uname"             ohos:height="match_content"             ohos:width="160vp"             ohos:layout_alignment="vertical_center"             ohos:padding="5vp"             ohos:text="我是一只鱼"             ohos:text_color="#FFA09E9E"             ohos:text_size="16vp"/>          <Text             ohos:id="$+id:comment_content"             ohos:height="match_content"             ohos:width="match_parent"             ohos:layout_alignment="vertical_center"             ohos:multiple_lines="true"             ohos:padding="5vp"             ohos:text="这是一条评论"             ohos:text_color="$color:default_black_color"             ohos:text_size="16vp"/>          <Text             ohos:id="$+id:comment_date"             ohos:height="match_content"             ohos:width="match_content"             ohos:layout_alignment="vertical_center"             ohos:padding="5vp"             ohos:text="2天前"             ohos:text_color="#FFA09E9E"             ohos:text_size="16vp"/>      </DirectionalLayout>      <DirectionalLayout         ohos:height="match_content"         ohos:width="match_content"         ohos:id="$+id:goods_view"         ohos:align_parent_right="true"         ohos:padding="5vp"         ohos:right_margin="5vp"         ohos:right_of="$id:comment_item_content">          <Image             ohos:id="$+id:good_icon"             ohos:height="25vp"             ohos:width="match_parent"             ohos:image_src="$media:ic_great"             ohos:scale_mode="stretch"             ohos:top_margin="13vp"             />          <Text             ohos:id="$+id:comment_goods"             ohos:height="match_content"             ohos:width="match_parent"             ohos:text="42"             ohos:text_alignment="center"             ohos:text_color="#FFA09E9E"             ohos:text_size="12vp"></Text>      </DirectionalLayout>      <DirectionalLayout         ohos:height="match_content"         ohos:width="match_parent"         ohos:align_bottom="$id:comment_item_content">         <Component             ohos:id="$+id:device_item_divider"             ohos:height="1vp"             ohos:width="match_parent"             ohos:background_element="$graphic:list_divider"/>     </DirectionalLayout> </DependentLayout> 

3.3.Java代码

创建评论列表提供程序类 CommentItemProvider.java

public class CommentItemProvider extends BaseItemProvider {      private static final HiLogLabel LABEL = new HiLogLabel(0, 0, "=>CommentsItemProvider");     private final Context context;     private final List<CommentModel> list;     private AbilitySlice abilitySlice;      /**      * Initialization      */     public CommentItemProvider(Context context, List<CommentModel> list, AbilitySlice slice) {          this.context = context;         this.list = list;         this.abilitySlice = slice;     }      @Override     public int getCount() {          return list == null ? 0 : list.size();     }      @Override     public Object getItem(int position) {          if (list != null && position >= 0 && position < list.size()) {              return list.get(position);         }         return new CommentModel();     }      public void addComment(CommentModel comment) {          if (comment == null) return;          list.add(0, comment);         notifyDataSetItemInserted(0);     }      @Override     public long getItemId(int position) {          return position;     }      @Override     public Component getComponent(int position, Component convertComponent, ComponentContainer componentContainer) {          final Component cpt;         if (convertComponent == null) {              cpt = LayoutScatter.getInstance(context).parse(ResourceTable.Layout_comments_item, null, false);         } else {              cpt = convertComponent;         }           CommentModel item = list.get(position);         //评论人头像         Image headerIcon = (Image) cpt.findComponentById(ResourceTable.Id_header_item_icon);         headerIcon.setPixelMap(ResourceTable.Media_ic_header);          //评论人名称         Text uName = (Text) cpt.findComponentById(ResourceTable.Id_comment_uname);         uName.setText(item.getuName());          //评论内容         Text uContent = (Text) cpt.findComponentById(ResourceTable.Id_comment_content);         uContent.setText(item.getCommentContent());         //点击事件         uContent.setClickedListener(component -> {              DependentLayout commentDialog = (DependentLayout) abilitySlice.findComponentById(ResourceTable.Id_comments_dialog);             if (commentDialog.getVisibility() == Component.VISIBLE) {                  commentDialog.setVisibility(Component.VISIBLE);             }             TextField comment = (TextField) abilitySlice.findComponentById(ResourceTable.Id_comment_tf);             comment.setText("");             comment.setHint("回复 " + item.getuName() + ":");             comment.requestFocus();         });           //评论日期         Text uDate = (Text) cpt.findComponentById(ResourceTable.Id_comment_date);         uDate.setText(item.getCommentDate());          //已赞数         Text goods = (Text) cpt.findComponentById(ResourceTable.Id_comment_goods);         HiLog.debug(LABEL, "goods:" + item.getCommentGoods());         goods.setText(item.getCommentGoods() + "");          //点赞         Image greatImage = (Image) cpt.findComponentById(ResourceTable.Id_good_icon);         //点赞加一         greatImage.setClickedListener(component1 -> {              greatImage.setPixelMap(ResourceTable.Media_ic_great_red);             goods.setTextColor(Color.RED);             goods.setText((item.getCommentGoods() + 1) + "");         });          if (position == list.size() - 1) {              Component divider = cpt.findComponentById(ResourceTable.Id_device_item_divider);             divider.setVisibility(Component.INVISIBLE);         }          return cpt;     } } 

 初始化评论列表和评论功能 VideoPlayAbilitySlice.java

/**  * 初始化评论列表  */ private void initComments(AbilitySlice slice) {      //评论列表,以及设置点击的监听事件、传递数据     ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_comments_container);     List<CommentModel> list = new ArrayList<>();     for (int i = 0; i < 10; i++) {          CommentModel obj = new CommentModel();         obj.setuId(i + "");         obj.setuName(getRandomUname());         obj.setCommentContent(getRandomText());         obj.setCommentDate("刚刚");         obj.setCommentGoods(new Random().nextInt(100));         list.add(obj);     }      //容器绑定数据提供程序     provider = new CommentItemProvider(this, list, slice);     listContainer.setItemProvider(provider);      Component sendComment = findComponentById(ResourceTable.Id_sent_comment);     TextField comment = (TextField) findComponentById(ResourceTable.Id_comment_tf);      //评论功能     sendComment.setClickedListener(component -> {          if (comment.getText().isEmpty()) {              new ToastDialog(getContext()).setText("评论不能为空").show();             return;         }         CommentModel model = new CommentModel();         model.setCommentContent(comment.getText());         model.setuId(UUID.randomUUID().toString());         model.setuName("robot");         model.setCommentDate("刚刚");          //添加到数据提供程序中         provider.addComment(model);          comment.setText("");         //评论数+1         commentsText.setText(String.valueOf(Integer.valueOf(comments) + 1));          new ToastDialog(getContext()).setText("评论成功").show();      }); } 

问题总结

1.播放器列表滑动时,会重复添加播放组件的问题

2.评论功能,输入框跟随输入法调整位置的问题(待完善)

3.播放列表滑动时,根据ScrollView的位置控制视频播放(待完善)

4.播放列表中播放视频进度同步到播放详情页的问题(待完善)

文章相关附件可以点击下面的原文链接前往下载

https://harmonyos.51cto.com/resource/1338

想了解更多内容,请访问:

和华为官方合作共建的鸿蒙技术社区

https://harmonyos.51cto.com

-->

分享到:

滇ICP备2023006006号-16