2021-06-28 14:18:59
0
`
前言
对于教育类App来说,一般都具有课程分类,包括我们程序员学习技术,也如此。简单的说,一个程序员社区,必然有众多技术分类,比如有的学习Python,有的学习Java鸿蒙技术,有的对OpenCV感兴趣。
而教育类App,如果能通过鸿蒙的卡片功能,将课程分类放在显眼的地方,那么用户就可以很容易直达自己感兴趣的知识社区进行学习,非常的方便。
所以,掌握好鸿蒙卡片功能,能够在细微的体验上,让用户感到贴心。下面,我们来讲解这款教育类专栏分类,如何通过卡片进行直达。
创建一个Java项目与卡片
首先,我们需要创建一个纯Java项目,如下图所示:
接着,在生成的Java鸿蒙项目中,点击entry-src右键创建Service Widget一个2*4的卡片布局:
创建完成之后,项目下面会生成一个java-widget文件,以及js卡片布局文件。如下图所示:
这样你运行项目,默认会显示鸿蒙开发工具提供给你的2*4布局卡片。但是我们需要将卡片的功能换成技术社区的直接跳转,接下来,我们来构建卡片。
完成卡片布局
如上图所示,我们的整体布局并没有变,但是后面的图片以及前面的文字都发生了变化,而js文件下,有一个hml文件,这是一个类html语法的文件,我们只需要改变字符串字符串以及图片即可,代码如下(index.hml):
- <div class="div_basic_container">
- <stack class="main_sub_container" onclick="routerEvent">
- <image class="item_image" src="/common/homepage.png">
- </image>
- <div class="div_text_container">
- <text class="title">主页
- </text>
- </div>
- </stack>
- <div class="first_sub_container">
- <div class="item_first_container" onclick="routerEvent1">
- <text class="text_item1">Python
- </text>
- </div>
- <div class="item_second_container" onclick="routerEvent2">
- <text class="text_item2">OpenCV
- </text>
- </div>
- </div>
- <div class="second_sub_container">
- <div class="item_first_container" onclick="routerEvent3">
- <text class="text_item3">鸿蒙开发
- </text>
- </div>
- <div class="item_second_container" onclick="routerEvent4">
- <text class="text_item4">量化交易
- </text>
- </div>
- </div>
- </div>
复制代码
接下来,我们需要弄清楚,js卡片布局是如何跳转到Java界面的,我们从上面的js文件发现,还有一个index.json。没错,样式由index.css产生,但跳转以及与用户的交互全在index.json文件中,代码如下(index.json):
- {
- "data": {
- "title": "HomePage",
- "textContent1": "Python",
- "textContent2": "OpenCV",
- "textContent3": "Harmony",
- "textContent4": "Search"
- },
- "actions": {
- "routerEvent": {
- "action": "router",
- "abilityName": "com.liyuanjinglyj.javacarddemo.widget.WidgetAbility",
- "params": {
- "message": "{{title}}"
- }
- },
- "routerEvent1": {
- "action": "router",
- "abilityName": "com.liyuanjinglyj.javacarddemo.widget.WidgetAbility",
- "params": {
- "message": "{{textContent1}}"
- }
- },
- "routerEvent2": {
- "action": "router",
- "abilityName": "com.liyuanjinglyj.javacarddemo.widget.WidgetAbility",
- "params": {
- "message": "{{textContent2}}"
- }
- },
- "routerEvent3": {
- "action": "router",
- "abilityName": "com.liyuanjinglyj.javacarddemo.widget.WidgetAbility",
- "params": {
- "message": "{{textContent3}}"
- }
- },
- "routerEvent4": {
- "action": "router",
- "abilityName": "com.liyuanjinglyj.javacarddemo.widget.WidgetAbility",
- "params": {
- "message": "{{textContent4}}"
- }
- }
- }
- }
复制代码
如上面代码所示,action表示这是路由跳转,其中,abilityName表示关联的Java卡片生成类,而params表示传递的参数。当然,params并不是界面的跳转参数,而是告诉Java你需要跳转到哪个界面。
我们来看看WidgetImpl类的实现代码:
- public class WidgetImpl extends FormController {
- @Override
- public Class<? extends AbilitySlice> getRoutePageSlice(Intent intent) {
- HiLog.info(TAG, "set route page slice.");
- String param = intent.getStringParam("params");
- ZSONObject zsonObject = ZSONObject.stringToZSON(param);
- switch (zsonObject.getString("message")) {
- case "HomePage":
- return MainAbilitySlice.class;
- case "Python":
- return FunctionPythonSlice.class;
- case "OpenCV":
- return FunctionOpenCVSlice.class;
- case "Harmony":
- return FunctionHarmonySlice.class;
- case "Search":
- return FunctionSearchSlice.class;
- default:
- return null;
- }
- }
- }
复制代码 这里大部分代码我们都可以忽略,只需要关心getRoutePageSlice方法即可,可以看到,我们在index.json中params指定的参数,就是我们需要跳转的Java界面,这里通过switch寻找我们卡片传递的参数,然后跳转到指定的界面。
比如,这里用户如果需要学习python,那么就会传递python参数,然后选择FunctionPythonSlice界面进行跳转。其他的类同。
实现卡片跳转界面
对于App来说,不同的界面的社区往往会有不同的数据,而每个数据又是通过json返回的,那么就会有不同的json接口提供给我们。
这里,我们来实现FunctionPythonSlice,代码如下:
- public class FunctionPythonSlice extends AbilitySlice {
- private String url="https://harmony-1300376177.cos.ap-shanghai.myqcloud.com/python_item.json";
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent((ComponentContainer) LYJUtils.getListContainer(url,this));
- }
- }
复制代码 这里通过博主自定义的工具类返回一个ListContainer界面,因为每个卡片上的功能只是跳转的知识不同,但数据样式基本一样。而ListContainer界面的生成代码如下(LYJUtils):
- public class LYJUtils {
- public static ListContainer getListContainer(String url, AbilitySlice abilitySlice){
- ListContainer listContainer=new ListContainer(null);
- listContainer.setLayoutConfig(
- new StackLayout.LayoutConfig(
- ComponentContainer.LayoutConfig.MATCH_PARENT,
- ComponentContainer.LayoutConfig.MATCH_PARENT
- ));
- ZZRHttp.get(url, new ZZRCallBack.CallBackString() {
- @Override
- public void onFailure(int code, String errorMessage) {
- //错误处理
- }
- @Override
- public void onResponse(String response) {
- //http访问成功,此部分内容在主线程中工作;
- HiJson hiJson = new HiJson(response);
- int counts=hiJson.get("news_item").count();
- List<InfoItem> infoItemList=new ArrayList<>();
- for(int i=0;i<counts;i++){
- InfoItem infoItem=new InfoItem();
- infoItem.setTitle(hiJson.get("news_item").get(i).value("title"));
- infoItem.setDigest(hiJson.get("news_item").get(i).value("digest"));
- infoItem.setUrl(hiJson.get("news_item").get(i).value("url"));
- infoItem.setThumb_url(hiJson.get("news_item").get(i).value("thumb_url"));
- infoItemList.add(infoItem);
- }
- InfoItemListProvider infoItemListProvider=new InfoItemListProvider(infoItemList, abilitySlice);
- listContainer.setItemProvider(infoItemListProvider);
- listContainer.setItemClickedListener(new ListContainer.ItemClickedListener() {
- @Override
- public void onItemClicked(ListContainer listContainer, Component component, int i, long l) {
- Intent intent=new Intent();
- intent.setParam("url",infoItemList.get(i).getUrl());
- abilitySlice.present(new WebViewAbilitySlice(),intent);
- }
- });
- }
- });
- return listContainer;
- }
- }
复制代码 其他卡片功能的界面基本一致,唯有url提供的json接口不一样。当然,这里还涉及ListContainer适配器,代码如下(InfoItemListProvider):
- public class InfoItemListProvider extends BaseItemProvider {
- private List<InfoItem> infoItemList=new ArrayList<>();
- private AbilitySlice abilitySlice;
- HiLogLabel label=new HiLogLabel(HiLog.LOG_APP, 0x00201, "TAG");
- public InfoItemListProvider(List<InfoItem> infoItemList,AbilitySlice abilitySlice) {
- this.infoItemList=infoItemList;
- this.abilitySlice=abilitySlice;
- HiLog.error(label,String.valueOf(infoItemList.size())+"11111");
- }
- @Override
- public int getCount() {
- return infoItemList == null ? 0 : infoItemList.size();
- }
- @Override
- public Object getItem(int i) {
- if (infoItemList != null && i >= 0 && i < infoItemList.size()){
- return infoItemList.get(i);
- }
- return null;
- }
- @Override
- public long getItemId(int i) {
- return i;
- }
- @Override
- public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
- final Component cpt;
- if (component == null) {
- cpt = LayoutScatter.getInstance(this.abilitySlice).parse(ResourceTable.Layout_infoitem_listitem, null, false);
- } else {
- cpt = component;
- }
- InfoItem infoItem = this.infoItemList.get(i);
- HiLog.error(label,String.valueOf(i)+"11111");
- Text title=(Text)cpt.findComponentById(ResourceTable.Id_infoitem_listitem_title);
- title.setText(infoItem.getTitle());
- Image image=(Image)cpt.findComponentById(ResourceTable.Id_infoitem_listitem_image);
- new ImageNetWork(this.abilitySlice,image,infoItem.getThumb_url()).start();
- return cpt;
- }
- }
复制代码 获取ListContainer列表的实体类(InfoItem.java)如下所示:
- public class InfoItem {
- String title;//标题
- String digest;//描述
- String url;//文章链接
- String thumb_url;//文章头图链接
- public InfoItem(String title,String digest,String url,String thumb_url) {
- this.title=title;
- this.digest=digest;
- this.url=url;
- this.thumb_url=thumb_url;
- }
- public InfoItem() {
- super();
- }
- public String getTitle() {
- return title;
- }
- public void setTitle(String title) {
- this.title = title;
- }
- public String getDigest() {
- return digest;
- }
- public void setDigest(String digest) {
- this.digest = digest;
- }
- public String getUrl() {
- return url;
- }
- public void setUrl(String url) {
- this.url = url;
- }
- public String getThumb_url() {
- return thumb_url;
- }
- public void setThumb_url(String thumb_url) {
- this.thumb_url = thumb_url;
- }
- }
复制代码
当然,这里还涉及列表的样式(infoitem_listitem.xml):
- <DirectionalLayout
- xmlns:ohos="http://schemas.huawei.com/res/ohos"
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:margin="10vp"
- ohos:alpha="0.5"
- ohos:background_element="$graphic:listitem_backgroud"
- ohos:orientation="vertical">
- <Image
- ohos:id="$+id:infoitem_listitem_image"
- ohos:height="150vp"
- ohos:width="match_parent"
- ohos:scale_mode="stretch"/>
- <Text
- ohos:id="$+id:infoitem_listitem_title"
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:text_size="18vp"
- ohos:multiple_lines="true"
- ohos:text_alignment="left"
- ohos:bottom_margin="5vp"
- ohos:left_margin="2vp"
- ohos:right_margin="2vp"
- ohos:top_margin="5vp"
- ohos:text_color="#0000FF"/>
- </DirectionalLayout>
复制代码 WebView文章详情界面
除此之外,我们还要实现ListContainer的跳转界面。因为这是网站的内容,我们只需要通过WebView进行加载即可。(WebViewAbilitySlice)代码如下:
- public class WebViewAbilitySlice extends AbilitySlice {
- HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "TAG");
- private WebView webView;
- private static String EXAMPLE_URL;
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_web_view);
- this.webView=(WebView)this.findComponentById(ResourceTable.Id_ability_web_view_webview);
- this.webView.getWebConfig().setJavaScriptPermit(true);
- if(intent != null) {
- EXAMPLE_URL = intent.getStringParam("url");
- this.webView.setWebAgent(new ExampleWebAgent());
- this.webView.load(EXAMPLE_URL);
- }
- }
- private class ExampleWebAgent extends WebAgent {
- @Override
- public boolean isNeedLoadUrl(WebView webview, ResourceRequest request) {
- Uri uri = request.getRequestUrl();
- if (EXAMPLE_URL.equals(uri.getDecodedHost())) {
- // 由WebView通过默认方式处理
- return false;
- }
- // 增加开发者自定义逻辑
- return super.isNeedLoadUrl(webview, request);
- }
- }
- @Override
- public void onActive() {
- super.onActive();
- }
- @Override
- public void onForeground(Intent intent) {
- super.onForeground(intent);
- }
- }
复制代码 鸿蒙提供给我们的Java WebView组件默认是直接跳转到浏览器的,为了让其在App内部显示,我们需要通过setWebAgent()方法进行设置。
而样式文件这里就不展示了,就只有一个WebView组件。
主页TabList与PageSlider联动
在众多的App中,我们能看到顶部标题栏可以进行滑动的切换页面,而这里我们也来认真实现卡片跳转的主页界面。
(MainAbilitySlice)代码如下:
- public class MainAbilitySlice extends AbilitySlice {
- HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "TAG");
- private PageSlider pageSlider;
- private TabList tabList;
- private String[] tab_str_list = {"推荐", "Python", "OpenCV", "鸿蒙开发"};
- @Override
- public void onStart(Intent intent) {
- super.onStart(intent);
- super.setUIContent(ResourceTable.Layout_ability_main);
- this.pageSlider = (PageSlider) findComponentById(ResourceTable.Id_ability_main_pageslider);
- this.pageSlider.setProvider(new MyPageProvider(getData(), this));
- this.tabList = (TabList) findComponentById(ResourceTable.Id_ability_main_tablist);
- for (int i = 0; i < tab_str_list.length; i++) {
- TabList.Tab tab = tabList.new Tab(getContext());
- tab.setText(tab_str_list[i]);
- tab.setLayoutConfig(
- new StackLayout.LayoutConfig(
- ComponentContainer.LayoutConfig.MATCH_CONTENT,
- ComponentContainer.LayoutConfig.MATCH_PARENT
- ));
- this.tabList.addTab(tab);
- if (i == 0) {
- tab.select();
- }
- }
- this.tabList.addTabSelectedListener(new TabList.TabSelectedListener() {
- @Override
- public void onSelected(TabList.Tab tab) {
- //当某个Tab从未选中状态变为选中状态时的回调
- pageSlider.setCurrentPage(tab.getPosition());
- }
- @Override
- public void onUnselected(TabList.Tab tab) {
- //当某个Tab从选中状态变为未选中状态时的回调
- }
- @Override
- public void onReselected(TabList.Tab tab) {
- //当某个Tab已处于选中状态,再次被点击时的状态回调
- }
- });
- pageSlider.addPageChangedListener(new PageSlider.PageChangedListener() {
- @Override
- public void onPageSliding(int itemPos, float itemPosOffset, int itemPosPixles) {
- }
- @Override
- public void onPageSlideStateChanged(int state) {
- }
- @Override
- public void onPageChosen(int itemPos) {
- tabList.selectTabAt(itemPos);
- }
- });
- }
- private List<String> getData(){
- List<String> stringList=new ArrayList<>();
- stringList.add("https://harmony-1300376177.cos.ap-shanghai.myqcloud.com/swiper_item.json");
- stringList.add("https://harmony-1300376177.cos.ap-shanghai.myqcloud.com/python_item.json");
- stringList.add("https://harmony-1300376177.cos.ap-shanghai.myqcloud.com/opencv_item.json");
- stringList.add("https://harmony-1300376177.cos.ap-shanghai.myqcloud.com/harmony_item.json");
- return stringList;
- }
复制代码 主页的布局文件(ability_main.xml)代码如下所示:
- <?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">
- <TabList
- ohos:id="$+id:ability_main_tablist"
- ohos:height="match_content"
- ohos:width="match_parent"
- ohos:tab_margin="12vp"
- ohos:text_alignment="center"
- ohos:orientation="horizontal"
- ohos:fixed_mode="true"
- ohos:text_size="20vp"
- ohos:normal_text_color="#808080"
- ohos:selected_text_color="#000000"
- ohos:selected_tab_indicator_color="#FF0000"
- ohos:selected_tab_indicator_height="3vp"/>
- <PageSlider
- ohos:id="$+id:ability_main_pageslider"
- ohos:height="match_parent"
- ohos:width="match_parent"
- ohos:layout_alignment="center"/>
- </DirectionalLayout>
复制代码 ListContainer需要适配器进行适配,PageSlider同样也是需要,我们需要给PageSlider提供不同的链接,然后PageSlider单个页面的ListContainer根据这些链接接口获取不同的知识列表。(MyPageProvider)代码如下:
- public class MyPageProvider extends PageSliderProvider {
- HiLogLabel label = new HiLogLabel(HiLog.LOG_APP, 0x00201, "TAG");
- private AbilitySlice abilitySlice;
- private List<String> stringList;
- public MyPageProvider(List<String> list,AbilitySlice abilitySlice){
- this.stringList=list;
- this.abilitySlice=abilitySlice;
- }
- @Override
- public int getCount() {
- return this.stringList.size();
- }
- @Override
- public Object createPageInContainer(ComponentContainer componentContainer, int i) {
- final String url = this.stringList.get(i);
- ListContainer listContainer=new ListContainer(null);
- listContainer.setLayoutConfig(
- new StackLayout.LayoutConfig(
- ComponentContainer.LayoutConfig.MATCH_PARENT,
- ComponentContainer.LayoutConfig.MATCH_PARENT
- ));
- ZZRHttp.get(url, new ZZRCallBack.CallBackString() {
- @Override
- public void onFailure(int code, String errorMessage) {
- //错误处理
- }
- @Override
- public void onResponse(String response) {
- //http访问成功,此部分内容在主线程中工作;
- //可以更新UI等操作,但请不要执行阻塞操作。
- HiJson hiJson = new HiJson(response);
- int counts=hiJson.get("news_item").count();
- List<InfoItem> infoItemList=new ArrayList<>();
- for(int i=0;i<counts;i++){
- InfoItem infoItem=new InfoItem();
- infoItem.setTitle(hiJson.get("news_item").get(i).value("title"));
- infoItem.setDigest(hiJson.get("news_item").get(i).value("digest"));
- infoItem.setUrl(hiJson.get("news_item").get(i).value("url"));
- infoItem.setThumb_url(hiJson.get("news_item").get(i).value("thumb_url"));
- infoItemList.add(infoItem);
- }
- InfoItemListProvider infoItemListProvider=new InfoItemListProvider(infoItemList, abilitySlice);
- listContainer.setItemProvider(infoItemListProvider);
- listContainer.setItemClickedListener(new ListContainer.ItemClickedListener() {
- @Override
- public void onItemClicked(ListContainer listContainer, Component component, int i, long l) {
- Intent intent=new Intent();
- intent.setParam("url",infoItemList.get(i).getUrl());
- abilitySlice.present(new WebViewAbilitySlice(),intent);
- }
- });
- }
- });
- componentContainer.addComponent(listContainer);
- return listContainer;
- }
- @Override
- public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
- componentContainer.removeComponent((Component) o);
- }
- @Override
- public boolean isPageMatchToObject(Component component, Object o) {
- return true;
- }
- }
复制代码 到这里,我们的教育类App卡片分类功能就全部完成了,实现的效果如顶部视频所示。
其他权限设置
当然,这款App卡片功能要能完美的运行,还不能少了部分权限具体配置文件config.json修改如下所示:
- "module": {
- "reqPermissions": [
- {
- "name": "ohos.permission.INTERNET"
- },
- {
- "name": "ohos.permission.GET_NETWORK_INFO"
- },
- {
- "name": "ohos.permission.SET_NETWORK_INFO"
- }
- ],
- "metaData": {
- "customizeData": [
- {
- "name": "hwc-theme",
- "value": "androidhwext:style/Theme.Emui.Light.NoTitleBar"
- }
- ]
- },
复制代码 其中,reqPermissions是权限,这里因为获取了网络的json数据,所以必须给与网络权限。而metaData是样式,这里我们去除了默认的标题栏。
`
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容图片侵权或者其他问题,请联系本站作侵删。
侵权投诉