Fellow Travellers

移动一张图专题分析

陈广禄
字数统计: 1.6k阅读时长: 7 min
2018/08/16 Share

移动一张图专题分析



简介

[专题模块为整个项目中的重要组成部分,也是不可或缺之一。用户可通过专题信息查看其主要层级结构和内部构造划分。对主要层级可进行收藏展示,便于直观查看。可手动点击某一层级结构打开对应图层,查看详细信息。]

列表主要分为两种结构,一种为树状结构、一种为层级结构。以相同的数据模型展示不同的列表结构,便于用户选择。

逻辑

列表项包括三角号小图标、收藏按钮和点击开关的按钮。根据不同情境分别设置相应的展示状态。

  • 当为树状结构时:首先初始化专题列表,通过Id展示最新列表。当点击Item项时,我们会记录专题的id,通过id找到子集列表数据,查看子集的type类型是否为“catalog”,如果是该类型,则会继续打开。直到我们点击Item项为“group”类型时,这时图层状态则不显示下一级别。 当我们点击开关状态时,获取子结点数据,将当前状态设置为打开,设置专题是否可见,根据id判断找到父级与子级,并更新整个专题的数据。当开关状态点击到“group”级别时,下一级别则是“layer”级别,图层状态则不显示下一级别。直接在图层上加载layer级别的数据。关闭时如果点击group级别的数据,则会直接关闭当前对应级别数据,父级状态为半开状态,如果关闭“catalog级则会将子级数据共同关闭,直到点击状态为“catalog”级别,对应“parentLayerId”=-1时,这时所有子级数据将全部关闭。
  • 当为层级结构时:当我们点击开关状态时,记录当前id,并通过id找到对应子级的信息,清空当前数据,将最新数据更新到列表上。关闭时当”parentLayerId!=-1”时,列表下方有一个按钮提示返回上一级,当点击按钮时会找到上一级别数据,将当前级别数据清空,并将父级数据展示到列表上,更新适配器。

Windows平台/AndroidStudio开发环境

重要代码实现



1. 通过ID获取列表,projectId刚开始传入-1.显示根目录列表:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
public void replaceAndShowListById(Context context, String projectId, boolean isOnlyShow) {
try {
List<ThemeInfo> themeInfoList=TopicLayerManager.getSubTopicList(context, projectId);
if (null != themeInfoList) {
if (null != showList) {
showList.clear();
}
}
listViewSetAdapter(themeInfoList);
if (!isOnlyShow && null != themeInfoList && themeInfoList.size() > 0) {
TotalApplication.getListIdInstance().clear();
TotalApplication.getListIdInstance().add(projectId);
}
} catch (Exception e) {
e.printStackTrace();
}
}

public synchronized void listViewSetAdapter(List<ThemeInfo> dmpList) {
if (null != dmpList && dmpList.size() > 0) {
if (null == projectAdapter) {
if (null != this.themeListView) {
this.showList = dmpList;
projectAdapter = new TopicAdapter(this.context, this.showList, handler, isGradedData);
this.themeListView.setAdapter(projectAdapter);
}
} else {
this.showList = dmpList;
projectAdapter.setThemeInfoList(this.showList);
}
}
}


2. 列表Item的点击事件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
public synchronized void clickItemResponse(Context context, int position) throws Exception {
if (null != showList) {
ThemeInfo node = showList.get(position);
if (JudgeNullUtil.ObjIsNull(node)) {
return;
}
List<ThemeInfo> dmpList = new ArrayList<>();
String projectId = node.getId();
String type = node.getType();
if (projectId != null && projectId.length() > 0 && Constants.TYPE_CATLOG.equals(type)) {
dmpList = TopicLayerManager.getSubTopicList(context, projectId);
}

if (null != dmpList && dmpList.size() > 0) {
if (isGradedData) {
if (projectId != null && projectId.length() > 0) {
if (!node.isLeaf()) {
node.setExpand(!node.isExpand());
if (node.isExpand()) {
for (ThemeInfo cNode : dmpList) {
cNode.setLevel(node.getLevel() + 1);
}
showList.addAll(position + 1, dmpList);
listViewSetAdapter(showList);
} else {
List<ThemeInfo> rmList = new ArrayList<>();
TopicUtil.getAllChildren(node, rmList, showList, false);
showList.removeAll(rmList);
listViewSetAdapter(showList);
}
TotalApplication.getListIdInstance().add(projectId);
}
}
} else {
if (projectId != null && projectId.length() > 0) {
showList = dmpList;
listViewSetAdapter(showList);
TotalApplication.getListIdInstance().add(projectId);
}
}
}
}
}


3. 开关按钮的点击事件:

public static void projectSwitch(Context context, Handler handler, List<ThemeInfo> themeInfoList, ThemeInfo info, TopicAdapter.ViewHolder finalHolder, boolean isGradedData) {
       List<ThemeInfo> parents = new ArrayList<>();
       TopicUtil.getAllParent(info, parents, themeInfoList, false);

       List<ThemeInfo> childrens = new ArrayList<>();
       TopicUtil.getAllChildren(info, childrens, themeInfoList, false);
       String openStatus = info.getOpenStatus();
       if (!openStatus.equals(Constants.TOPIC_STATUS_OFF)) {
           finalHolder.isOpen.setImageResource(R.mipmap.topic_off);
           info.setOpenStatus(Constants.TOPIC_STATUS_OFF);
           TopicUtil.closeCurrentNode(info, themeInfoList, false);
       } else {
           finalHolder.isOpen.setImageResource(R.mipmap.topic_on);
           info.setOpenStatus(Constants.TOPIC_STATUS_ON);
           for (ThemeInfo node : childrens) {
               node.setOpenStatus(Constants.TOPIC_STATUS_ON);
           }
           for (ThemeInfo node : parents) {
               node.setOpenStatus(Constants.TOPIC_STATUS_ON);
           }
       }
       if (JudgeNullUtil.ObjIsNull(info)) {
           return;
       }
       TopicUtil.topicSwitchVisible(context, info, handler, isGradedData);
   }


4.通过图层id显示专题图层:

/**
    * 通过图层id显示专题图层。
    *
    * @param context      上下文
    * @param visibleInfos 当前需要显示的图层
    */
   public static void setLayerVisible(Context context, List<ThemeInfo> visibleInfos, String currentStatus) throws Exception {
       if (JudgeNullUtil.ObjIsNull(visibleInfos)) {
           return;
       }
       boolean isOpenLayer = false;
       if (!currentStatus.equals(Constants.TOPIC_STATUS_OFF)) {
           isOpenLayer = true;
       }
       if(App.isOnLineData){
           onlineVisibleLayer(context, visibleInfos, isOpenLayer);
       }else{
           offlineVisibleLayer(visibleInfos,isOpenLayer);
       }
   }


5.更新专题数据:

/**
 * 更新专题某一层级数据或整个专题数据源
 */
   public static void updateThemeList(Context context, List<ThemeInfo> themeList) throws Exception {
       App appCtx = (App) context.getApplicationContext();
       appCtx.getDataSource().setTheme(themeList);
   }
/**
    * 更新子级目录专题数据
    */
   public static List<ThemeInfo> updateSubData(ThemeInfo subThemeInfo, List<ThemeInfo> themeList) throws Exception {
       if (subThemeInfo == null) {
           return themeList;
       }
       String currentId = subThemeInfo.getId();
       if (currentId == null || JudgeNullUtil.ObjIsNull(themeList)) {
           return themeList;
       }
       List<String> subLayerIds = getSubLayerIds(currentId, themeList);
       if (JudgeNullUtil.ObjIsNull(subLayerIds)) {
           return themeList;
       }
       assert subLayerIds != null;
       for (int i = 0; i < subLayerIds.size(); i++) {
           String subId = subLayerIds.get(i);
           subThemeInfo.setId(subId);
           String type = getThemeType(subThemeInfo, themeList);
           updateCurrentData(subThemeInfo, themeList);
           if (type == null) {
               continue;
           }
           if (type.equals(Constants.TYPE_CATLOG)) {
               updateSubData(subThemeInfo, themeList);
           }
       }
       return themeList;
   }


6. 更新layer数据:

/**
  * 设置layer显示状态
  * @param layer专题图层
  * @param visibleIds 图层id
  */
public static void updateLayerVisible(Layer layer, int[] visibleIds, boolean isOpenLayer) throws Exception {
        if (layer == null) {
            return;
        }
        if (layer instanceof ArcGISDynamicMapServiceLayer) {
            ArcGISDynamicMapServiceLayer dynamicLayer = (ArcGISDynamicMapServiceLayer) layer;
            refreshDynamicLayer(visibleIds, dynamicLayer, isOpenLayer);
        } else {
            layer.setVisible(isOpenLayer);
        }
    }
/**
     * 根据visibleIds 更新DymicLayer
     * @param visibleIds   layer Ids
     * @param dynamicLayer 当前需要刷新的图层
     */
    private static void refreshDynamicLayer(int[] visibleIds, ArcGISDynamicMapServiceLayer dynamicLayer, boolean isOpenLayer) throws Exception {
        if (dynamicLayer == null) {
            return;
        }
        ArcGISLayerInfo[] arcGISLayerInfos = dynamicLayer.getAllLayers();
        if (visibleIds.length > arcGISLayerInfos.length) {
            return;
        }
        ArcGISLayerInfo layerInfo;
        for (int index : visibleIds) {
            if (index < 0) {
                continue;
            }
            layerInfo = arcGISLayerInfos[index];
            if (layerInfo == null) {
                continue;
            }
            boolean isVisible = layerInfo.isVisible();
            ArcGISLayerInfo layerParentInfo = layerInfo.getParentLayer();

            if (layerParentInfo != null) {
                boolean parentVisible = layerParentInfo.isVisible();
                if (isOpenLayer) {
                    if (!parentVisible) {
                        layerParentInfo.setVisible(true);
                    }
                } else {
                    if (parentVisible) {
                        layerParentInfo.setVisible(false);
                    }
                }
            }
            if (isOpenLayer) {
                if (!isVisible) {
                    layerInfo.setVisible(true);
                }
            } else {
                if (isVisible) {
                    layerInfo.setVisible(false);
                }
            }
        }
        if (!dynamicLayer.isVisible()) {
            dynamicLayer.setVisible(true);
        }
        dynamicLayer.refresh();
    }



结语

专题模块的开发提高了项目的灵活性和通透性,大大缩短了用户点击搜索的时间,保证了多层级结构加载时层与层之间的联系不冲突,确保它们之间稳定性。查询时可通过坐标点查询多个图层所对应信息,大大缩短了查询效率,确保项目的顺利进行。为后期新功能迭代打下坚实基础,提高用户体验。

CATALOG
  1. 1. 移动一张图专题分析
    1. 1.1. 简介
    2. 1.2. 逻辑
      1. 1.2.1. Windows平台/AndroidStudio开发环境
    3. 1.3. 重要代码实现
      1. 1.3.0.1. 1. 通过ID获取列表,projectId刚开始传入-1.显示根目录列表:
      2. 1.3.0.2. 2. 列表Item的点击事件:
      3. 1.3.0.3. 3. 开关按钮的点击事件:
      4. 1.3.0.4. 4.通过图层id显示专题图层:
      5. 1.3.0.5. 5.更新专题数据:
      6. 1.3.0.6. 6. 更新layer数据:
  2. 1.4. 结语