ScrollView 嵌套 ListContainer
就 ScrollView 嵌套 ListContainer 的滑动问题,社区问答中也是遇见了两次提问的小伙伴。在帮助第一个小伙解决这个问题的时候,我提供了一个思路和以前在写 Android ScrollView 嵌套 ListView 滑动问题的解决方法。经过方法的修改也是解决了他的问题,后续没有再把这个问题解决的全过程记录下来,直到发现有第二个小伙伴也遇到了同样的问题,准备把这个小问题写成一篇帖子,希望后面再遇到“ScrollView 嵌套 ListContainer 滑动问题”的同学可以帮助到你们。
思路
一、ScrollView 嵌套 ListContainer 想让 ListContainer 不滑动,只滑动 ScrollView。在 Android 中有个东西叫做拦截器,ScrollView 的拦截器,通过对拦截器的赋值达到只滑动 ScrollView,不滑动 ListView。
调用方式
因为 ScrollView 继承自 ViewGroup,在 ViewGroup 中有有 dispatchTouchEvent()这个方法,
但是在 HarmonyOS 中,ScrollView 继承自 ComponentContainer,而且在 ComponentContainer 中没有类似于 dispatchTouchEvent 的拦截器方法,那么拦截器不能搞就得换方法。二、这时第二个思路也成型了,因为 ScrollView 的高度是根据它内部的组件的高度变化的,当内部的组件高度大于手机屏幕的高度时会出现 ScrollView 的滚动,反之不会出现。那么就只能从 ScrollView 的高度入手了,要改变 ScrollView 的高度就必须去改变它内部组件的高度,那么问题来了 ScrollView 嵌套 ListContainer,ListContainer 的高度最大只能到屏幕大小或者是固定于屏幕内部,一旦高度达到所设置的高度,ListContainer 就会出现自动滚动此时 ScrollView 的滚动也会失效,这里是焦点的关系滑动动作取到的焦点会在它当前组件上。思路到这里也就清晰了,ListContainer 的高度大于原始设置的高度时会发生滑动,ScrollView 在内部组件高度大于手机屏幕时才会滑动。那么如果把 ListContainer 的高度设置成一个动态的固定值,ListContainer 的数据永远不会被填充满,ListContainer 就不会出现滑动。随即 ListContainer 的高度如果大于了屏幕的高度 ScrollView 就会滑动。OK,问题找到了,解决 ListContainer 的动态高度就解决的滑动冲突。
解决问题
首先我找到了当初写 Android 时动态 Listview 高度的方法。这里就粘一下图
思路没有变,将每次 listview 的 Item 高度相加作为 listview 的整体高度,listview 的高度就是动态的变化,listview 的高度会根据数据的增加而变化。==根据参考==下面开始写代码首先整体布局文件,很简单 ScrollView 嵌套 ListContainer 为了效果明显加入了一个图片
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent">
<ScrollView
ohos:id="$+id:view"
ohos:height="match_parent"
ohos:width="match_parent">
<!--设置DirectionalLayout的高度为match_parent-->
<DirectionalLayout
ohos:height="match_parent"
ohos:width="match_parent"
ohos:alignment="center"
ohos:orientation="vertical">
<Image
ohos:id="$+id:img"
ohos:height="100vp"
ohos:width="100vp"
ohos:image_src="$media:icon"></Image>
<ListContainer
ohos:id="$+id:list"
ohos:height="match_parent"
ohos:width="match_parent"
></ListContainer>
</DirectionalLayout>
</ScrollView>
</DirectionalLayout>
复制代码
ListContainer 的 Item 布局,这里很简单就放一个文本
<?xml version="1.0" encoding="utf-8"?>
<DirectionalLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_content"
ohos:width="match_parent"
ohos:left_margin="16vp"
ohos:right_margin="16vp"
ohos:orientation="vertical">
<Text
ohos:id="$+id:item_index"
ohos:height="match_content"
ohos:width="match_content"
ohos:padding="4vp"
ohos:text="Item0"
ohos:text_size="20fp"
ohos:layout_alignment="center"/>
</DirectionalLayout>
复制代码
创建 SampleItem.java,作为 ListContainer 的数据包装类。
public class SampleItem {
private String name;
public SampleItem(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
复制代码
写一个 ListContainer 的适配器用于放数据
public class SampleItemProvider extends BaseItemProvider {
private List<SampleItem> list;
private AbilitySlice slice;
public SampleItemProvider(List<SampleItem> list, AbilitySlice slice) {
this.list = list;
this.slice = 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 null;
}
@Override
public long getItemId(int position) {
return position;
}
@Override
public Component getComponent(int position, Component component, ComponentContainer componentContainer) {
final Component cpt;
if (component == null) {
cpt = LayoutScatter.getInstance(slice).parse(ResourceTable.Layout_item_sample, null, false);
} else {
cpt = component;
}
SampleItem sampleItem = list.get(position);
Text text = (Text) cpt.findComponentById(ResourceTable.Id_item_index);
text.setText(sampleItem.getName());
return cpt;
}
}
复制代码
在 Java 代码中添加 ListContainer 的数据,并适配其数据结构。还没有加动态高度的方法。
public class MainAbilitySlice extends AbilitySlice {
@Override
public void onStart(Intent intent) {
super.onStart(intent);
super.setUIContent(ResourceTable.Layout_ability_main);
initListContainer();
}
private void initListContainer() {
ListContainer listContainer = (ListContainer) findComponentById(ResourceTable.Id_list);
List<SampleItem> list = getData();
listContainer.setBoundarySwitch(true); //添加分界线
SampleItemProvider sampleItemProvider = new SampleItemProvider(list, this);
listContainer.setItemProvider(sampleItemProvider);
}
private ArrayList<SampleItem> getData() {
ArrayList<SampleItem> list = new ArrayList<>();
for (int i = 0; i < 30; i++) {
list.add(new SampleItem("Item" + i));
}
return list;
}
}
复制代码
查看效果
编写自定义高度方法:
private void setListContainerHeight(ListContainer listContainer) {
//获取当前listContainer的适配器
BaseItemProvider BaseItemProvider = listContainer.getItemProvider();
if (BaseItemProvider == null){
return;
}
int itemHeight = 0;
for (int i = 0; i < BaseItemProvider.getCount(); i++) {
//循环将listContainer适配器的Item数据进行累加
Component listItem = BaseItemProvider.getComponent(i, null, listContainer);
itemHeight += listItem.getHeight();
}
//对当前listContainer进行高度赋值
ComponentContainer.LayoutConfig config = listContainer.getLayoutConfig();
//这边加上(listContainer.getBoundaryThickness() * (BaseItemProvider.getCount()+1))
//listContainer.getBoundaryThickness() 就是分界线的高度
//(BaseItemProvider.getCount()+1) 是Item的数量 加1 是因为顶部还有一条分界线
config.height = itemHeight
+ (listContainer.getBoundaryThickness() * (BaseItemProvider.getCount()+1));
//赋值
listContainer.setLayoutConfig(config);
}
复制代码
调用方法:
实现效果:
出问题了,不能滑动!!!!!!!
==找到了,问题在布局中==
重新运行,查看结果:
OK 了,以达到了最终的效果。代码放在了下面的资源链接里,大家可以进行参考。
源代码
评论