学习使用鸿蒙基础控件,实现类似新闻类app顶部tab效果。
先上demo图:
实现步骤:
1、使用模板创建项目,自带开屏页;
2、修改main布局文件,添加tabList,pageSlider控件,tabList相关属性设置,也可在代码中实现;
<?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:orientation="vertical">
<TabList
ohos:id="$+id:title_tabs"
ohos:height="48vp"
ohos:width="match_parent"
ohos:background_element="$color:copyright_text_color"
ohos:fixed_mode="false"
ohos:normal_text_color="#ffffff"
ohos:orientation="horizontal"
ohos:selected_tab_indicator_color="#ff0000"
ohos:selected_tab_indicator_height="2vp"
ohos:selected_text_color="#ff0000"
ohos:tab_margin="5vp"
ohos:text_alignment="center"
ohos:text_size="18fp"
/>
<PageSlider
ohos:id="$+id:pager"
ohos:height="match_parent"
ohos:width="match_parent"
/>
</DirectionalLayout>
3、鸿蒙支持各类数据xml定义,与安卓类似,数组资源文件定义(base/element/strarray.json);
{
"strarray": [
{
"name": "tab_title",
"value": [
{
"value": "推荐"
},
{
"value": "热点"
},
{
"value": "NBA"
},
{
"value": "美图"
},
{
"value": "疫情"
},
{
"value": "本地"
},
{
"value": "军事"
},
{
"value": "投资"
},
{
"value": "金融"
}
]
}
]
}
4、开发实现,代码较为基础,不做多解释,如有疑问或想法可在评论区交流;
原本期望使用fraction+pageSlider实现整体页面切换,查阅官方资料,暂不支持。无奈用component代替fraction。
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initView();
initData();
}
//初始化控件
private void initView() {
tabList = (TabList) findComponentById(ResourceTable.Id_title_tabs);
pageSlider = (PageSlider) findComponentById(ResourceTable.Id_pager);
tabList.addTabSelectedListener(this);
pageSlider.addPageChangedListener(this);
}
// tab与page数据初始化
private void initData() {
try {
String[] tabsTitle = getResourceManager().getElement(ResourceTable.Strarray_tab_title).getStringArray();
for (String title: tabsTitle){
TabList.Tab tab = tabList.new Tab(getContext());
tab.setText(title);
tabList.addTab(tab);
}
tabList.selectTabAt(0); //选中0位置
pageSlider.setProvider(new MainPagerAdapter(initPageSliderViewData()));
pageSlider.setCurrentPage(0);
pageSlider.setReboundEffect(true);
pageSlider.setCentralScrollMode(true);
} catch (IOException | NotExistException | WrongTypeException e) {
e.printStackTrace();
}
}
private ArrayList<Component> initPageSliderViewData() {
int pageSize = tabList.getTabCount();
ArrayList<Component> pages = new ArrayList<>();
ViewCreateHelper viewCreateHelper = new ViewCreateHelper(getContext());
for (int i = 0; i < pageSize; i++) {
pages.add(viewCreateHelper.createView(tabList.getTabAt(i).getText()));
}
return pages;
}
①PageSlider适配器,使用方式与viewPager类似;
public class MainPagerAdapter extends PageSliderProvider {
private List<Component> pages;
public MainPagerAdapter(ArrayList<Component> pages) {
this.pages = pages;
}
@Override
public int getCount() {
return pages == null ? 0 : pages.size();
}
@Override
public Object createPageInContainer(ComponentContainer componentContainer, int i) {
componentContainer.addComponent(pages.get(i));
return componentContainer;
}
@Override
public void destroyPageFromContainer(ComponentContainer componentContainer, int i, Object o) {
componentContainer.removeComponent(pages.get(i));
}
@Override
public boolean isPageMatchToObject(Component component, Object o) {
return component == o;
}
}
②ViewCreaterHelper用于创建page页;
public final class ViewCreateHelper {
private Context slice;
private HashMap<String, ListAdapter> cache;
public ViewCreateHelper(Context abilitySlice) {
this.slice = abilitySlice;
cache = new HashMap<>();
}
public Component createView(String title) {
Component mainComponent =
LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_pager_item, null, false);
if (!(mainComponent instanceof ComponentContainer)) {
return null;
}
ComponentContainer rootLayout = (ComponentContainer) mainComponent;
initView(mainComponent,title);
return rootLayout;
}
public void initView(Component mainComponent,String title) {
// 列表
ListContainer listContainer = (ListContainer) mainComponent.findComponentById(ResourceTable.Id_list_main);
ListAdapter<NewsInfo> listAdapter = new ListAdapter<NewsInfo>(slice, ResourceTable.Layout_item_news_layout, getData(0, title)) {
@Override
public void convert(ViewHolder viewHolder, NewsInfo item, int position) {
viewHolder.setText(ResourceTable.Id_item_news_title, item.getTitle());
viewHolder.setText(ResourceTable.Id_item_news_desc, item.getDescription());
}
};
listContainer.setItemProvider(listAdapter);
listContainer.setItemClickedListener((list, component, i, l) -> {
// Intent in = new Intent();
// in.setElementName("", component.getContext().getBundleName(), DetailAbility.class.getName());
// slice.startAbility(in, 0);
});
cache.put(title, listAdapter);
}
public List<NewsInfo> getData(int tab, String title) {
List<NewsInfo> curData = new ArrayList<>();
for (int i = 0; i < 20; i++) {
NewsInfo info = new NewsInfo();
info.setTitle("标题:" + title + i);
info.setDescription("我是描述啦" + title + Math.random());
curData.add(info);
}
return curData;
}
}
③list适配器;
public abstract class ListAdapter<T> extends BaseItemProvider {
private List<T> data;
private Context ct;
private int itemId;
public ListAdapter(Context ct, int itemId, List<T> data) {
this.data = data;
this.ct = ct;
this.itemId = itemId;
}
public abstract void convert(ViewHolder viewHolder, T item, int position);
@Override
public int getCount() {
return data == null ? 0 : data.size();
}
@Override
public T getItem(int i) {
return data.get(i);
}
@Override
public long getItemId(int i) {
return i;
}
@Override
public Component getComponent(int i, Component component, ComponentContainer componentContainer) {
ViewHolder viewHolder = null;
if (component == null) {
Component itemView = LayoutScatter.getInstance(ct).parse(itemId, componentContainer, false);
viewHolder = new ViewHolder(ct, itemView, componentContainer, i);
viewHolder.layoutId = itemId;
} else {
Object object = component.getTag();
if (object instanceof ViewHolder) {
viewHolder = (ViewHolder) object;
viewHolder.position = i;
}
}
convert(viewHolder, getItem(i), i);
return viewHolder == null ? null : viewHolder.getComponentView();
}
}
④ViewHolder,可自行添加其他逻辑;
public class ViewHolder {
int position;
int layoutId;
private Component component;
private Context context;
private HashMap<Integer, Component> views;
ViewHolder(Context context, Component itemView, ComponentContainer parent, int position) {
this.context = context;
this.component = itemView;
this.position = position;
views = new HashMap<>(0);
component.setTag(this);
}
@SuppressWarnings("unchecked")
public <T extends Component> T getView(int viewId) {
Component view = views.get(viewId);
if (view == null) {
view = component.findComponentById(viewId);
views.put(viewId, view);
}
return (T) view;
}
Component getComponentView() {
return component;
}
public void setText(int viewId, String text) {
Text tv = getView(viewId);
tv.setText(text);
}
public void setImageResource(int viewId, int resId) {
Image image = getView(viewId);
image.setPixelMap(resId);
image.setScaleMode(Image.ScaleMode.STRETCH);
}
}
End
其他资源文件未列举出,请参考完整demo。
github Demo源码
遗留问题思考
1、当点击tab切换时,若tab未完全显示,最好可以自动滑动展示完整tab;
2、未做下拉刷新与加载更多,涉及到滑动事件冲突;