2013-02-15 139 views
1

我正在寻找一种优雅的方式来显示片段上的层次结构(树)。多个片段的树状视图

我的想法是在不同的片段上显示每个级别。通过点击一片叶子,我可以进入层次结构中的下一个层次(如果在这里也有漂亮的滑动动画会很好)。最后,我会得到一个点,我有叶子,这应该导致一个细节视图。

我已经知道树视图实现(如http://code.google.com/p/tree-view-list-android/),但我想要在不同的片段上有每个级别。如果在Mac文件浏览器中显示大屏幕(平板电脑)上的几个级别,也会很酷。

主要的原因是,我想要从服务器根据请求加载每个级别的数据(树是相当大的),其次我想要有一个清晰的布局。另一方面,我不希望每个级别的片段都分开执行,因为深度可以从分支到分支。

我的数据当前是在表单中,每个树节点都由具有id,名称,TreeElementType(节点或叶子)和TreeElements列表的TreeElement对象表示为子节点。如果这个结构不得不被修改,那将是可行的。

任何人都可以想出一个很好的方法来实现这一点?

贝斯特,埃里克

回答

1

我终于找到了一个工作的解决方案:

我TreeElement类看起来是这样的:因此

public class TreeElement 
{ 
private int id; 
private TreeElementType type; 
private String name; 

/** 
* List that holds a set of all the children tree elements. 
*/ 
private List<TreeElement> children = new ArrayList<TreeElement>(); 

/** 
* List that holds a set of the courses associated to the TreeElement. 
* 
* @see Course 
*/ 
private List<Course> courses = new ArrayList<Course>(); 

public TreeElement() 
{ 
    this.type = TreeElementType.NODE; 
    this.children = new ArrayList<TreeElement>(); 
} 

public TreeElement(int id) 
{ 
    this(); 
    this.id = id; 
} 

public TreeElement(int id, String name) 
{ 
    this(id); 
    this.name = name; 
} 

public TreeElement(int id, TreeElementType type, String name) 
{ 
    this(id, name); 
    this.type = type; 
} 

public int getId() 
{ 
    return id; 
} 

public void setId(int id) 
{ 
    this.id = id; 
} 

public TreeElementType getType() 
{ 
    return type; 
} 

public void setType(TreeElementType type) 
{ 
    this.type = type; 
} 

public String getName() 
{ 
    return name; 
} 

public void setName(String name) 
{ 
    this.name = name; 
} 

public List<TreeElement> getChildren() { 
    return children; 
} 

public void setChildren(List<TreeElement> children) { 
    this.children = children; 
} 

public void addChild(TreeElement child) { 
    this.children.add(child); 
} 

public void addChildren(List<TreeElement> children) { 
    this.children.addAll(children); 
} 

public List<Course> getCourses() { 
    return courses; 
} 

public void setCourses(List<Course> courses) { 
    this.courses = courses; 
} 

public void addCourse(Course course) { 
    this.courses.add(course); 
} 

public void addCourses(List<Course> courses) { 
    this.courses.addAll(courses); 
} 
} 

这些TreeElements产生分层式树。每个TreeElement可以额外容纳一些我想在树中显示的课程。

拿着所有的寻呼机与页面片段是这样的一个:

public class BrowserSectionFragment extends Fragment { 
private BrowserFragmentPagerAdapter mAdapter; 
private ViewPager mPager; 
private List<Fragment> fragments = new Vector<Fragment>(); 

public BrowserSectionFragment() { 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container, 
     Bundle savedInstanceState) { 

    View view = inflater.inflate(R.layout.fragment_browser, container, false); 

    /* 
    * Add the root TreeElement-fragment, holding the categories of lowest 
    * level. 
    */ 
    fragments.add(new BrowserPageFragment(this,TreeContainer.getTreeElement(TreeContainer.ROOT_ID))); 

    mAdapter = new BrowserFragmentPagerAdapter(this.getFragmentManager(), fragments); 

    mPager = (ViewPager) view.findViewById(R.id.pager); 
    mPager.setAdapter(mAdapter); 

    mPager.setOnPageChangeListener(new OnPageChangeListener() { 
     @Override 
     public void onPageScrollStateChanged(int arg0) {} 

     @Override 
     public void onPageScrolled(int arg0, float arg1, int arg2) {} 

     @Override 
     public void onPageSelected(int arg0) { 
      while (arg0 < fragments.size()-1) { 
       fragments.remove(fragments.size()-1); 
      } 

      /* 
      * notify the adapter of the changes being made 
      * causes the adapter to check all elements, if they are still in the 
      * list of fragments 
      */ 
      mAdapter.notifyDataSetChanged(); 
     } 
    }); 

    return view; 
} 

/** 
* Adds a new fragment to the fragment manager. The data is taken from 
* the children list of the TreeElement. 
* 
* @param clickedElement 
*/ 
public void addFragmentFromElement(TreeElement clickedElement) { 
    fragments.add(new BrowserPageFragment((this),clickedElement)); 
    mPager.setCurrentItem(fragments.size()-1, true); 
} 
} 

现在我需要一个PagerAdapter,在这种情况下FragmentStatePagerAdapter,组织片段:

public class BrowserFragmentPagerAdapter extends FragmentStatePagerAdapter { 
/** 
* List that holds all the fragments which are currently accessible 
* through the Pager. 
*/ 
private List<Fragment> mFragments; 

/** 
* Constructor that initializes the list of fragments. 
* 
* @param fm FragmentsManager 
* @param fragments 
*/ 
public BrowserFragmentPagerAdapter(FragmentManager fm, List<Fragment> fragments) { 
    super(fm); 
    mFragments = fragments; 
} 

@Override 
public Fragment getItem(int position) { 
    return mFragments.get(position); 
} 

@Override 
public int getCount() { 
    return mFragments.size(); 
} 

@Override 
public int getItemPosition(Object item) { 
    /* 
    * See if fragment is still in the list. 
    * If yes, the position in the list is returned, if not, POSITION_NONE, 
    * which causes the Pager to delete the related view. 
    */ 
    Fragment fragment = (Fragment) item; 
    int position = mFragments.indexOf(fragment); 

    if (position >= 0) { 
     return position; 
    } else { 
     return POSITION_NONE; 
    } 
} 
} 

最后我实现了显示ListView的PageFragment:

public class BrowserPageFragment extends ListFragment { 
public static final String ARG_ELEMENT_ID = "element_id"; 
TreeElement element; 
BrowserSectionFragment frag; 
Context context; 

public BrowserPageFragment() { 
    super(); 
} 

public BrowserPageFragment(BrowserSectionFragment frag, TreeElement element) { 
    this(); 
    this.frag = frag; 
    this.element = element; 
} 

@Override 
public View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) { 
    /* Creating an array adapter to store the list of countries **/ 
    BrowserListAdapter adapter = new BrowserListAdapter(inflater.getContext(),element); 
    /* Setting the list adapter for the ListFragment */ 
    setListAdapter(adapter); 

    return super.onCreateView(inflater, container, savedInstanceState); 
} 

@Override 
public void onListItemClick(ListView l, View v, int position, long id) { 

    Object clickedElement = l.getAdapter().getItem(position); 

    if (clickedElement instanceof TreeElement) { 
     frag.addFragmentFromElement((TreeElement) clickedElement); 
    } else if (clickedElement instanceof Course) { 
     /* 
     * Start a new fragment which shows a detail view of the course. 
     */ 
     Course course = (Course) clickedElement; 
     int courseId = course.getId(); 
     CourseContainer.setCourse(courseId, course); 

     Fragment fragment = new DetailsFragment(); 
     Bundle args = new Bundle(); 
     args.putInt(DetailsFragment.ARG_COURSE_NUMBER, courseId); 
     fragment.setArguments(args); 

     getActivity().getSupportFragmentManager().beginTransaction().replace(R.id.container, fragment).commit(); 
    } 
} 
} 

To使其完成,我的自定义ListAdapter看起来像这样:

public class BrowserListAdapter extends BaseAdapter { 
private final LayoutInflater mInflater; 
TreeElement element; 
List<Object> elements = new ArrayList<Object>(); 

public BrowserListAdapter(Context context, TreeElement element) { 
    mInflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE); 
    this.element = element; 

    elements.addAll(element.getChildren()); 
    elements.addAll(element.getCourses()); 
} 

@Override 
public int getCount() { 
    return elements.size(); 
} 

@Override 
public Object getItem(int position) { 
    return elements.get(position); 
} 

@Override 
public long getItemId(int position) { 
    Object item = elements.get(position); 
    if (item instanceof TreeElement) { 
     return ((TreeElement) item).getId(); 
    } else if (item instanceof Course) { 
     return ((Course) item).getId(); 
    } 

    return -1; 
} 

@Override 
public View getView(int position, View convertView, ViewGroup parent) { 
    View itemView = (View) mInflater.inflate(android.R.layout.simple_list_item_1, parent, false); 
    bindView(itemView, position); 
    return itemView; 
} 

private void bindView(View itemView, int position) { 
    Object item = getItem(position); 
    String text = null; 

    if (item instanceof TreeElement) { 
     text = ((TreeElement) item).getName(); 
    } else if (item instanceof Course) { 
     text = ((Course) item).getTitle(); 
    } 

    itemView.setId((int) getItemId(position)); 
    TextView title = (TextView) itemView; 
    title.setText(text); 
} 
} 

也许这个解决方案可以帮助某人。这里唯一剩下的问题是:

  • BrowserPageFragment的构造函数有一个带参数的构造函数,这不是很好。
  • 当改变方向时,寻呼机跳转到第一页。
  • 后退按钮不会转到上一页。