2013-02-15 6 views
1

Я ищу элегантный способ показать иерархию (дерево) на фрагментах.Tree View для нескольких фрагментов

Моя идея - показать каждый уровень на отдельном фрагменте. Нажимая на лист, я бы поднялся на следующий уровень в иерархии (было бы неплохо иметь здесь довольно скользящую анимацию). Наконец, я бы подошел к точке, где у меня есть листья, что должно привести к детальному представлению.

Я уже знаю реализации в виде дерева (например, http://code.google.com/p/tree-view-list-android/), но хочу иметь каждый уровень на отдельном фрагменте. Было бы также здорово показать несколько уровней рядом друг с другом на больших экранах (планшетах), например, в файловом браузере Mac.

Основная причина заключается в том, что я хочу загрузить данные для каждого уровня с сервера по запросу (дерево довольно большое), а во-вторых, я хочу иметь четкий макет. С другой стороны, я не хочу, чтобы каждый фрагмент уровня реализовывался отдельно, так как глубина очень сильно от ветки к ветке.

Мои данные в настоящее время представлены в форме, что каждый узел дерева представлен объектом TreeElement с идентификатором, именем, TreeElementType (узел или лист) и списком TreeElements как дочерними. Если эту структуру нужно будет изменить, это будет выполнимо.

Может ли кто-нибудь подумать о хорошем способе реализовать это?

Бест, Erik

ответ

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, организовать Fragments:

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; 
    } 
} 
} 

Наконец я реализован файл PageFragment, который показывает ListView:

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(); 
    } 
} 
} 

К сделайте это, мой пользовательский 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 имеет конструктор с аргументами, что не очень приятно.
  • При изменении ориентации пейджер переходит на первую страницу.
  • Задняя кнопка не переходит на предыдущую страницу.