【木棉花】ImageCoverFlow开源组件助力七夕 原创 精华
前言
深圳大学木棉花组织是一群热衷于学习鸿蒙相关知识和开发鸿蒙相关应用的开发者们,欢迎与各位感兴趣的开发者一起学习鸿蒙开发,相互交流、共同进步。
更多资料请关注我们的项目 : Awesome-Harmony_木棉花
概述
七夕已过,但是属于你的浪漫永远不会缺席,赶紧动手为你的心上人制作一个专属的相册,不是七夕也能存在莫大的惊喜!
效果如下:左右滑动时图片会切换
点击“自动播放”按钮时,图片会顺序切换。这是按钮变为“停止播放”,点击“停止播放”按钮时,图片会停止自动切换
正文
一、创建一个空白的工程
1. 安装和配置DevEco Studio 2.1 Release
DevEco Studio 2.1 Release下载、DevEco Studio 2.1 Release安装
2. 创建一个Empty Java Phone应用
DevEco Studio下载安装成功后,打开DevEco Studio,点击左上角的File,点击New,再选择New Project,选择Empty Ability(Java)选项,点击Next按钮。
将文件命名为QiXiFestival(文件名不能出现中文或者特殊字符,否则将无法成功创建项目文件),选择保存路径,选择API5,设备勾选Phone,最后点击Finish按钮。
3. 准备工作
在entry>src>main>config.json文件中最下方"launchType": "standard"的后面添加以下代码,这样就可以实现去掉应用上方的标签栏了。
config.json最下面部分代码:
"orientation": "unspecified",
"name": "com.test.qixifestival.MainAbility",
"icon": "$media:icon",
"description": "$string:mainability_description",
"label": "$string:entry_MainAbility",
"type": "page",
"launchType": "standard",
"metaData": {
"customizeData": [
{
"name": "hwc-theme",
"value": "androidhwext:style/Theme.Emui.Light.NoTitleBar",
"extra": ""
}
]
}
}
]
}
}
二、引入开源组件ImageCoverFlow
1. 引入开源包
在QiXiFestival>build.gradle添加以下代码:
allprojects{
repositories{
mavenCentral()
}
}
在QiXiFestival>entry>build.gradle的dependencies内添加第三方包。
dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar', '*.har'])
testImplementation 'junit:junit:4.13'
ohosTestImplementation 'com.huawei.ohos.testkit:runner:1.0.0.200'
implementation 'io.openharmony.tpc.thirdlib:image-cover-flow:1.0.2'
}
decc {
supportType = ['html','xml']
}
重新生成Gradle即可。
2. 添加主页面的布局
在QiXiFestival>entry>src>main>resources>base>layout>ability_main.xml添加布局代码。
删除已有的Text组件。添加com.dolphinwang.imagecoverflow.CoverFlowView组件,将id属性的值设置为$+id:coverflow,以通过MainAbilitySlice.java中根据唯一标识设置相应内容。将height和width属性的值分别设置为match_parent和match_parent。orientation属性的值设置为vertical,layout_alignment属性的值设置为center。
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<com.dolphinwang.imagecoverflow.CoverFlowView
ohos:id="$+id:coverflow"
ohos:width="match_parent"
ohos:height="400vp"
ohos:orientation="vertical"
ohos:layout_alignment="center"/>
</DirectionalLayout>
3. 实现3D相册
由于相册界面显示的一组图片是通过CoverFlowView控件实现的,因此需要创建一个数据适配器ResourceUtils对该控件进行数据适配。
创建ResourceUtils.java:
package com.test.qixi_java.slice;
import ohos.app.Context;
import ohos.global.resource.NotExistException;
import ohos.global.resource.RawFileEntry;
import ohos.global.resource.Resource;
import ohos.global.resource.ResourceManager;
import ohos.global.resource.WrongTypeException;
import ohos.media.image.ImageSource;
import ohos.media.image.PixelMap;
import java.io.IOException;
import java.util.Optional;
public class ResourceUtils {
public static Optional<PixelMap> getPixelMap(Context context, int id) {
String path = getPathById(context, id);
if (path == null || path.trim().length() == 0) {
return Optional.empty();
}
RawFileEntry assetManager = context.getResourceManager().getRawFileEntry(path);
ImageSource.SourceOptions options = new ImageSource.SourceOptions();
options.formatHint = "image/png";
ImageSource.DecodingOptions decodingOptions = new ImageSource.DecodingOptions();
try {
Resource asset = assetManager.openRawFile();
ImageSource source = ImageSource.create(asset, options);
return Optional.ofNullable(source.createPixelmap(decodingOptions));
} catch (IOException ex) {
}
return Optional.empty();
}
public static String getPathById(Context context, int id) {
String path = "";
if (context == null) {
return path;
}
ResourceManager manager = context.getResourceManager();
if (manager == null) {
return path;
}
try {
path = manager.getMediaPath(id);
} catch (IOException | NotExistException | WrongTypeException ex) {
}
return path;
}
}
将事先准备好的图片放到QiXiFestival>entry>src>main>resources>media中,并且名字命名为image1、image2、image3、image4、image5、image6、image7。
由于相册界面主要显示一组图片,每张图片都有自己的图片ID和标题ID的属性,所以为了方便起见,我们新建一个MyCoverFlowAdapter类继承CoverFlowAdapter来存放图片的这些属性。在MyCoverFlowAdapter方法中将图片放到列表中,并且重写getCount()和getImage()方法。
创建MyCoverFlowAdapter.java:
package com.test.qixifestival.slice;
import com.dolphinwang.imagecoverflow.CoverFlowAdapter;
import com.test.qixifestival.ResourceTable;
import ohos.app.Context;
import ohos.media.image.PixelMap;
import java.util.ArrayList;
import java.util.List;
public class MyCoverFlowAdapter extends CoverFlowAdapter {
private List<PixelMap> mBitmapList = new ArrayList<>();
public MyCoverFlowAdapter(Context context) {
PixelMap image1 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image1).get();
PixelMap image2 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image2).get();
PixelMap image3 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image3).get();
PixelMap image4 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image4).get();
PixelMap image5 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image5).get();
PixelMap image6 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image6).get();
PixelMap image7 = ResourceUtils.getPixelMap(context, ResourceTable.Media_image7).get();
mBitmapList.add(image1);
mBitmapList.add(image2);
mBitmapList.add(image3);
mBitmapList.add(image4);
mBitmapList.add(image5);
mBitmapList.add(image6);
mBitmapList.add(image7);
}
@Override
public int getCount() {
return mBitmapList.size();
}
@Override
public PixelMap getImage(final int position) {
return mBitmapList.get(position);
}
}
在QiXiFestival>entry>src>main>java>com.test.qixifestival>slice>MainAbilitySlice.java编写以下代码。
添加一个CoverFlowView类型的名为mCoverFlowView的变量。添加一个名为initView的函数,对相册页面进行初始化。在生命周期事件函数onStart中调用函数initView,以实现对相册页面初始化:
public class MainAbilitySlice extends AbilitySlice {
private CoverFlowView mCoverFlowView;
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initView();
}
private void initView() {
Component component = findComponentById(ResourceTable.Id_coverflow);
if (component instanceof CoverFlowView) {
mCoverFlowView = (CoverFlowView) component;
}
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
}
添加一个名为initData函数,先对相册进行判断,如果相册为空,则返回。
setReflectionHeight为设置反射高度,设置为30。setVisibleImage为设置同时可见图片的数量,这里设置为5。引入扩展adapter。
为相册添加一个点击事件已达到通过左右滑动进行图片切换,在生命周期事件函数onStart中调用函数initData,以实现对相册数据初始化。
public class MainAbilitySlice extends AbilitySlice {
private CoverFlowView mCoverFlowView;
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initView();
initData();
}
private void initView() {
......
}
private void initData() {
if (mCoverFlowView == null) {
return;
}
mCoverFlowView.setReflectionHeight(30);
mCoverFlowView.setVisibleImage(5);
final MyCoverFlowAdapter adapter = new MyCoverFlowAdapter(this);
mCoverFlowView.setAdapter(adapter);
mCoverFlowView.setImageClickListener((coverFlowView, position) -> {
coverFlowView.setSelection(position);
});
}
......
}
三、实现图片自动播放
1. 实现主页面布局
打开ability_main.xml文件。
添加Button组件,将id属性的值设置为$+id:change_bitmap_button,以通过MainAbilitySlice.java中根据唯一标识设置点击事件。将height和width属性的值分别设置为50vp和200vp。text属性的值设置为“自动播放”,text_color属性的值设置为#ffffff,text_size属性的值设置为24vp,top_marginr属性的值设置为20vp,background_element属性的值设置为#5D3C51,layout_alignment属性的值设置为center。
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<com.dolphinwang.imagecoverflow.CoverFlowView
ohos:id="$+id:coverflow"
ohos:width="match_parent"
ohos:height="400vp"
ohos:orientation="vertical"
ohos:layout_alignment="center"/>
<Button
ohos:id="$+id:change_bitmap_button"
ohos:height="50vp"
ohos:width="200vp"
ohos:text="自动播放"
ohos:text_color="#ffffff"
ohos:text_size="24fp"
ohos:top_margin="20vp"
ohos:background_element="#5D3C51"
ohos:layout_alignment="center"/>
</DirectionalLayout>
2. 实现自动播放逻辑代码
添加一个Timer类型的变量time,以实现图片每隔一秒自动切换。添加一个String类型的变量text,以记录是否自动播放。添加一个int类型的变量number,以记录当前的图片是哪张。添加一个boolean类型的变量k,以记录是正序播放还是倒序播放。
在initData函数内,通过唯一标识符添加一个点击事件。先判断text为“自动播放”时,对time进行初始化,设置时间任务的延迟为0,间隔为1000ms即1秒,在时间任务中添加一个子线程,通过CoverFlowView的监听事件获取当前图片是哪张。如果number为0,即当前的图片为第一张,则k赋值为true,以实现图片正序切换;如果number为6,即当前的图片为最后一张,则k赋值为false,以实现图片倒序播放。通过setSelection设置当前的图片。最后根据k的值对number进行加1或减1,并且text设置为“停止播放”,按钮上的文本设置为text。
如果text为“停止播放”时,取消时间任务。对text设置为“自动播放”,按钮上的文本设置为text。
public class MainAbilitySlice extends AbilitySlice {
private CoverFlowView mCoverFlowView;
private static Timer time;
private static String text = "自动播放";
private static int number = 0;
private static boolean k = true;
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initView();
initData();
}
private void initView() {
......
}
private void initData() {
......
Button button = (Button) findComponentById(ResourceTable.Id_change_bitmap_button);
button.setClickedListener(new Component.ClickedListener() {
@Override
public void onClick(Component component) {
mCoverFlowView.setStateListener(new CoverFlowView.StateListener() {
@Override
public void imageOnTop(CoverFlowView coverFlowView, int i, float v, float v1, float v2, float v3) {
number = i;
}
@Override
public void invalidationCompleted(CoverFlowView coverFlowView) {
}
});
if(text == "自动播放"){
time = new Timer();
time.schedule(new TimerTask() {
@Override
public void run() {
getUITaskDispatcher().asyncDispatch(()->{
if(number == 0){
k = true;
}else if(number == 6){
k = false;
}
mCoverFlowView.setSelection(number);
if(k == true){
number++;
}else{
number--;
}
});
}
},0,1000);
text = "停止播放";
button.setText(text);
}else if(text == "停止播放"){
time.cancel();
text = "自动播放";
button.setText(text);
}
}
});
}
......
}
保存代码运行即可。
更多资料请关注我们的项目 : Awesome-Harmony_木棉花