接下来我们想通过一个文件浏览器应用,练习文件系统操作,文件表示等功能,本文首先说明获取并表示文件系统内容的方法。还是先看演示视频:
构建FileStore表示画面
首先为准备画面布局:
<?xml version="1.0" encoding="utf-8"?>
<xwg.filebrowser.DynamicLayout
xmlns:ohos="http://schemas.huawei.com/res/ohos"
ohos:height="match_parent"
ohos:width="match_parent"
ohos:background_element="$graphic:main_ability_title_background"
ohos:orientation="vertical">
<include
ohos:id="$id:app_bar"
ohos:height="match_content"
ohos:width="match_parent"
ohos:layout="$layout:app_bar_layout"/>
<xwg.filebrowser.fileitems.FileListContainer
ohos:id="$+id:list_container"
ohos:height="0"
ohos:weight="300"
ohos:width="match_parent"
ohos:layout_alignment="left"/>
<xwg.filebrowser.LayoutSeparator
ohos:id="$+id:seperator"
ohos:height="20vp"
ohos:width="match_parent"
ohos:background_element="#7F7F7F"/>
<DirectionalLayout
ohos:id="$+id:detail_view_container"
ohos:width="match_parent"
ohos:height="0"
ohos:weight = "300"/>
</xwg.filebrowser.DynamicLayout>
画面的上半部分是一个定制的FileListContainer类,它的功能有:
FileListContainer集中管理文件系统节点列表的表示功能。
在构造函数中做了以下几件事:
public class FileListContainer extends ListContainer {
public FileListContainer(Context context, AttrSet attrSet) {
super(context, attrSet);
enableScrollBar(Component.AXIS_Y, true);
setScrollbarThickness(50);
setScrollbarRoundRect(true);
setScrollbarRadius(20);
setScrollbarBackgroundColor(Color.LTGRAY);
setScrollbarColor(Color.DKGRAY);
disableFadeEffect(FadeEffectEnum.FADEEFFECT_SCROLLBAR);
BrowserItemProvider sampleItemProvider = new BrowserItemProvider(context);
setItemProvider(sampleItemProvider);
setItemSelectedListener(itemSelectedListener);
}
public interface SelectedListener{
public void onItemSelected(FileListContainer listContainer, BrowserItem item);
}
SelectedListener selectedListener = null;
public void setSelectedListener(SelectedListener listener){
selectedListener = listener;
}
ListContainer.ItemSelectedListener itemSelectedListener = new ListContainer.ItemSelectedListener(){
Component prevSelected = null;
@Override
public void onItemSelected(ListContainer listContainer, Component component, int i, long l) {
if(prevSelected != null){
FileListContainer.this.setComponentActive(prevSelected, false);
}
if(FileListContainer.this.selectedListener != null){
FileListContainer.this.selectedListener.onItemSelected(FileListContainer.this,
(BrowserItem)(FileListContainer.this.getItemProvider().getItem(i)));
}
FileListContainer.this.setComponentActive(component, true);
prevSelected = component;
}
};
void setComponentActive(Component component, boolean active){
ShapeElement bg = new ShapeElement();
if(active) {
bg.setRgbColor(RgbPalette.LIGHT_GRAY);
bg.setShape(ShapeElement.RECTANGLE);
component.setBackground(bg);
}
else{
component.setBackground(getBackgroundElement());
}
}
}
这个ItemSelectedListener处理选择项目的表示状态之后,将通知转发给自定义的SelectedListener,让开发者可以更简单地处理BrowserItem实例:
public class MainAbilitySlice extends AbilitySlice {
static final HiLogLabel LABEL = new HiLogLabel(HiLog.LOG_APP, 0x00101, "MainAbilitySlice");
private ViewCreateHelper viewCreateHelper;
@Override
public void onStart(Intent intent) {
setUIContent(ResourceTable.Layout_browser_ability);
initListContainer();
}
@Override
public void onActive() {
super.onActive();
}
@Override
public void onForeground(Intent intent) {
super.onForeground(intent);
}
FileListContainer.SelectedListener listener = new FileListContainer.SelectedListener() {
@Override
public void onItemSelected(FileListContainer listContainer, BrowserItem item) {
HiLog.info(LABEL, "MainAbilitySlice.onItemSelected, item=%{public}s!", item.getName());
ComponentContainer container =
(ComponentContainer)(MainAbilitySlice.this.findComponentById(ResourceTable.Id_detail_view_container));
item.buildView(container);
container.invalidate();
}
};
private void initListContainer() {
FileListContainer listContainer = (FileListContainer) findComponentById(ResourceTable.Id_list_container);
listContainer.setSelectedListener(listener);
}
}
获取FileStore信息
示例代码中定义了一个BaseItemProvider的派生类为FileListContainer 提供数据,其代码如下:
public class BrowserItemProvider extends BaseItemProvider {
private List<BrowserItem> list = new ArrayList<>();
private Context context;
public BrowserItemProvider(Context c) {
this.context = c;
FileSystem fs = FileSystems.getDefault();
Iterable<FileStore> stores = fs.getFileStores();
for(FileStore store : stores) {
list.add(new StoreItem(c, store));
}
}
@Override
public int getCount() {
return list == null ? 0 : list.size();
}
@Override
public Object getItem(int i) {
if (list != null && i >= 0 && i < list.size()){
return list.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(context).parse(ResourceTable.Layout_dir_item, null, false);
} else {
cpt = component;
}
BrowserItem item = list.get(i);
Text text = (Text) cpt.findComponentById(ResourceTable.Id_item_index);
text.setText(item.getName());
return cpt;
}
}
这些都是使用ListContainer的常规操作。BaseItemProvider和
生成表示信息
目前只是通过FileSystems获取FileStore列表并为每个FileStore实例生成了表示其详细信息的StoreItem。为了将来可以处理更多的数据类型,例如目录,文件等,这个StoreItem类继承自下面的BrowserItem类:
public abstract class BrowserItem {
String name;
Context context;
public BrowserItem(Context context, String name) {
this.context = context;
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
abstract public void buildView(ComponentContainer container);
}
BrowserItem类除了有一个name成员之外,声明了一个纯虚的用于构建详细信息表示视窗的buildView方法。buildView方法接受一个用于管理UI组件的容器组件,设计者可以以为这个组件添加下级组件的方式构建不同类型item的表示画面。
例如StoeItem:
public class StoreItem extends BrowserItem{
FileStore store;
public StoreItem(Context context, FileStore s) {
super(context, s.name());
store = s;
}
@Override
public void buildView(ComponentContainer container) {
container.removeAllComponents();
ComponentContainer child_container = (ComponentContainer)LayoutScatter.getInstance(context).parse(
ResourceTable.Layout_info_list,
null,
false);
ListContainer list_container = (ListContainer)child_container.findComponentById(
ResourceTable.Id_info_list_container);
InfoItemProvider provider = new InfoItemProvider(context);
try {
provider.addItem(new SimpleInfoItem("Name", store.name()));
provider.addItem(new SimpleInfoItem("ReadOnly", String.valueOf(store.isReadOnly())));
provider.addItem(new SimpleInfoItem("TotalSpace", String.valueOf(store.getTotalSpace()/1024) + " KB"));
provider.addItem(new SimpleInfoItem("UsableSpace", String.valueOf(store.getUsableSpace()/1024) + " KB"));
provider.addItem(new SimpleInfoItem("Type", store.type()));
} catch (IOException e) {
e.printStackTrace();
}
list_container.setItemProvider(provider);
container.addComponent(child_container);
}
}
buildView方法首先构建了根据指定的布局文件生成相应的组件,并为其中的ListContainer生成InfoItemProvider示例。接下来从FileStore获取各种信息并作为列表项添加到InfoItemProvider中。最后将生成的整个布局组件添加到通过参数指定的容器中即可。
参考资料
ListContainer
https://developer.harmonyos.com/cn/docs/documentation/doc-guides/ui-java-component-listcontainer-0000001060007847
FileSystems
https://developer.harmonyos.com/cn/docs/documentation/doc-references/filesystems-0000001054238505
FileSystem
https://developer.harmonyos.com/cn/docs/documentation/doc-references/filesystem-0000001054558507
FileStore
https://developer.harmonyos.com/cn/docs/documentation/doc-references/filestore-0000001054358485
参考代码
https://github.com/xueweiguo/Harmony/tree/master/FileBrowser
作者著作介绍
《实战Python设计模式》是作者去年3月份出版的技术书籍,该书利用Python 的标准GUI 工具包tkinter,通过可执行的示例对23 个设计模式逐个进行说明。这样一方面可以使读者了解真实的软件开发工作中每个设计模式的运用场景和想要解决的问题;另一方面通过对这些问题的解决过程进行说明,让读者明白在编写代码时如何判断使用设计模式的利弊,并合理运用设计模式。
对设计模式感兴趣而且希望随学随用的读者通过本书可以快速跨越从理解到运用的门槛;希望学习Python GUI 编程的读者可以将本书中的示例作为设计和开发的参考;使用Python 语言进行图像分析、数据处理工作的读者可以直接以本书中的示例为基础,迅速构建自己的系统架构。