2015-07-01 61 views
4

我想弄清楚如何在我的android应用程序(材料设计)工具栏中创建面包屑。Android材质设计 - 如何在工具栏中放置面包屑(导航)?

这可以在最新的Dropbox android应用程序中看到,其中的breadcrumb用于显示文件的导航。

我还发现一个图像(这是我从another similar question了),可以在这里看到:

enter image description here

你能指导我我该怎么办呢?

+0

由于面包屑位于工具栏下方,因此最有可能会有一个附加组件,它只与工具栏具有相同的背景色,而且它们之间没有边界。 –

+0

@GeraldSchneider,你知道如何实现这个组件吗? –

+0

我很确定这里有很多可用的库。 –

回答

2

我不认为你需要一个图书馆。如果你创建一个视图(也许是一个FrameLayout),然后你将它设置为背景颜色相同的工具栏,然后你把一个TextView里面,那么它就完成了。您甚至可以扩展TextView类并重写一些方法来为更改设置动画。您可以通过活动之间的意图传递面包屑的当前字符串,然后每个人都知道如何更新它。

3

我为一个应用程序创建了这个应用程序的一个工作示例,以为我会分享它,因为它变得比它需要大声混淆。也许这可以节省一些开发者很多的努力,应该没有必要:)

添加Horizo​​ntalScrollView您AppBarLayout(布局/ examplebreadcrumbs_layout

<android.support.v7.widget.AppBarLayout 
     android:id="@+id/app_bar" 
     style="@style/HeaderBar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content"> 

    <android.support.v7.widget.Toolbar 
     android:id="@+id/toolbar" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:background="?colorPrimary" 
     android:minHeight="?attr/actionBarSize" 
     app:contentInsetStart="72dp" 
     app:navigationContentDescription="up" /> 

    <HorizontalScrollView android:id="@+id/breadcrumb_wrapper" 
     android:layout_width="match_parent" 
     android:layout_height="50dp" 
     android:scrollbars="none"> 

     <LinearLayout android:id="@+id/breadcrumbs" 
      android:orientation="horizontal" 
      android:layout_width="wrap_content" 
      android:layout_height="match_parent" 
      android:layout_gravity="center_vertical" 
      android:gravity="center_vertical" 
      android:paddingEnd="@dimen/activity_horizontal_margin_2" 
      android:paddingStart="@dimen/activity_horizontal_margin_2"/> 

    </HorizontalScrollView> 

</android.support.v7.widget.AppBarLayout> 

创建的LinearLayout即会用于每个“面包屑”。你会膨胀每个相同的布局。 (布局/ breadcrumb_text

<LinearLayout android:id="@+id/crumb" 
    xmlns:tools="http://schemas.android.com/tools" 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:orientation="horizontal" 
    android:layout_width="wrap_content" 
    android:layout_height="match_parent"> 

    <TextView 
     android:id="@+id/crumb_arrow" 
     android:layout_width="wrap_content" 
     android:layout_height="match_parent" 
     android:visibility="gone" 
     android:gravity="center_vertical" 
     android:text="@string/greater_than" 
     android:padding="4dp" 
     android:fontFamily="sans-serif-condensed" 
     android:textSize="20sp" 
     android:textColor="@color/breadcrumb_text_dim" 
     android:textAllCaps="true" 
     tools:visibility="visible"/> 

    <TextView 
     android:id="@+id/crumb_text" 
     android:layout_width="wrap_content" 
     android:layout_height="match_parent" 
     android:padding="4dp" 
     android:gravity="center_vertical" 
     android:visibility="gone" 
     android:fontFamily="sans-serif" 
     android:textAllCaps="true" 
     android:textSize="14sp" 
     android:textColor="@color/breadcrumb_text" 
     android:background="?selectableItemBackground"/> 

</LinearLayout> 

ExampleBreadcrumbs演示基本的创建/更新/滚动到你可以很容易地添加到您的应用程序流量的方法。不是100%复制粘贴,因为你的应用会有所不同,这取决于你的面包屑添加到哪个活动和设置。如果你需要其他任何东西来使这个工作...让我知道。

public class ExampleBreadcrumbs extends AppCompatActivity { 

    private static final String ROOT_NODE = "root"; 

    private SparseArray<Long> levelNodeIds = new SparseArray<>(); 
    private SparseArray<String> levelNodeNames = new SparseArray<>(); 

    public int currentLevel = 0; 

    ViewGroup breadcrumbBar; 
    HorizontalScrollView breadcrumbWrapper; 

    String[] parents = new String[] {"Parent Item 1", "Parent Item 2", 
     "Parent Item 3", "Parent Item 4"}; 

    @Override protected void onCreate(Bundle savedInstanceState) { 
    super.onCreate(savedInstanceState); 
    setContentView(R.layout.examplebreadcrumbs_layout); 

    breadcrumbWrapper = ((HorizontalScrollView)findViewById(R.id.breadcrumb_wrapper)); 
    breadcrumbBar = (ViewGroup) findViewById(R.id.breadcrumbs); 

    // TODO setup your adapter or whatever 

    createParentNodes(); 
    } 

    @Override public void onBackPressed() { 
    switch (currentLevel) { 
     case 0: 
     super.onBackPressed(); 
     break; 
     case 1: 
     createParentNodes(); 
     adapter.notifyDataSetChanged(); 
     break; 
     default: 
     // Get values from level you are requesting, not current. 
     final long id = levelNodeIds.get(currentLevel - 1); 
     final String name = levelNodeNames.get(currentLevel - 1); 
     getChildren(id, name, -1); 
     break; 
    } 

    } 

    @Override public void onItemClick(View itemView, final String name) { 
    long nodeId = (Long) itemView.getTag(); 
    getChildren(nodeId, name, 1); 
    } 

    private void getChildren(final long nodeId, final String name, final int difference) { 
    if (nodeId != 0) { 
     // Example case using retrofit like setup 
     getChildren(nodeId, new Callback<NodesResponse>() { 
     @Override 
     public void onResponse(Call<NodesResponse> call, Response<NodesResponse> response) { 
      if (response.body() != null) { 
      if (response.body().getNodeObjs() != null && !response.body().getNodeObjs() 
       .isEmpty()) { 
       createChildNodes(nodeId, name, response.body().getNodeObjs(), difference); 
      } 
      } 
     } 

     @Override 
     public void onFailure(Call<NodesResponse> call, Throwable t) { // TODO} 
     }); 
    } else { 
     createParentNodes(); 
     adapter.notifyDataSetChanged(); 
    } 
    } 

    private void createParentNodes() { 
    currentLevel = 0; 
    levelNodeIds.put(currentLevel, 0L); 
    levelNodeNames.put(currentLevel, ROOT_NODE); 

    listItems.clear(); 
    int count = 0; 
    for(String parent : parents) { 
     listItems.add(new NodeObj(nodeId[count], parent, parentDescriptions[count])); 
     count++; 
    } 
    adapter.notifyDataSetChanged(); 
    levelNodeNames.put(currentLevel, ROOT_NODE); 
    updateBreadcrumbs(true); 
    } 

    private void createChildNodes(long id, String name, List<NodeObj> NodeObjs, int difference) { 
    listItems.clear(); 
    for (NodeObj obj : NodeObjs) { 
     listItems.add(new NodeObj(obj.getnodeId(), obj.getNodeTitle(), obj.getNodeDescription())); 
    } 
    adapter.notifyDataSetChanged(); 

    currentLevel = currentLevel + difference; 
    levelNodeIds.put(currentLevel, id); 
    levelNodeNames.put(currentLevel, name); 

    // If forward, it will create new node along with updating other nodes. 
    updateBreadcrumbs(difference > 0); 
    } 

    private void updateBreadcrumbs(boolean createNew) { 
    if (createNew) { 
     createBreadcrumb(); 
    } 
    // Loops and updates all breadcrumb nodes 
    updateBreadcrumbNodes(); 
    //printDebug(); 
    } 

    private void createBreadcrumb() { 
    boolean needToCreate = true; 

    // Remove view if one exists. 
    ViewGroup nodeToReplace = (ViewGroup) breadcrumbBar.getChildAt(currentLevel); 
    if (nodeToReplace != null) { 
     TextView toReplaceTextView = (TextView) nodeToReplace.findViewById(R.id.crumb_text); 
     // If node history is not the same, remove view and after. 
     if (toReplaceTextView.getText().equals(levelNodeNames.get(currentLevel))) { 
     needToCreate = false; 
     scrollIfBreadcrumbNotViewable(nodeToReplace); 
     } else { 
     needToCreate = true; 
     // Removes all nodes >= current level 
     for (int i = breadcrumbBar.getChildCount() - 1; i >= currentLevel; i--) { 
      breadcrumbBar.removeViewAt(i); 
     } 
     } 
    } 

    if (needToCreate) { 
     // Inflate new breadcrumb node. 
     final ViewGroup crumbLayout = (ViewGroup) LayoutInflater.from(this) 
      .inflate(R.layout.breadcrumb_text, appBarLayout, false); 
     crumbLayout.setTag(levelNodeIds.get(currentLevel)); 
     // Sets name of node (color gets updated in 'updateBreadcrumbNodes'). 
     TextView crumbTextView = (TextView) crumbLayout.findViewById(R.id.crumb_text); 
     crumbTextView.setVisibility(View.VISIBLE); 
     crumbTextView.setText(levelNodeNames.get(currentLevel)); 
     View crumbArrow = crumbLayout.findViewById(R.id.crumb_arrow); 
     crumbArrow.setVisibility(levelNodeNames.get(currentLevel).equals(ROOT_NODE) ? View.GONE : View.VISIBLE); 
     // Add new breadcrumb node to bar. 
     breadcrumbBar.addView(crumbLayout, currentLevel); 
     scrollIfBreadcrumbNotViewable(crumbLayout); 
     // Create click listener to jump to history. 
     crumbLayout.setOnClickListener(new View.OnClickListener() { 
     @Override public void onClick(View v) { 
      int viewIndex = breadcrumbBar.indexOfChild(v); 
      if (viewIndex == currentLevel) return; 
      TextView crumbText = (TextView) v.findViewById(R.id.crumb_text); 
      int index = levelNodeNames.indexOfValue(crumbText.getText().toString()); 
      long nodeId = (Long) v.getTag(); 
      getChildren(nodeId, levelNodeNames.get(index), viewIndex - currentLevel); 
     } 
     }); 
    } 

    } 

    private void updateBreadcrumbNodes() { 
    for (int i = 0; i < breadcrumbBar.getChildCount(); i++) { 
     boolean activeNode = i == (currentLevel); 
     ViewGroup node = (ViewGroup) breadcrumbBar.getChildAt(i); 
     TextView crumbTextView = ((TextView) node.findViewById(R.id.crumb_text)); 
     crumbTextView.setTextColor(activeNode ? ContextCompat.getColor(this, R.color.breadcrumb_text) : 
           ContextCompat.getColor(this, R.color.breadcrumb_text_dim)); 
    } 
    breadcrumbWrapper.fullScroll(HorizontalScrollView.FOCUS_BACKWARD); 
    } 

    private void scrollIfBreadcrumbNotViewable(final ViewGroup view) { 
    Rect scrollBounds = new Rect(); 
    toolbar.getHitRect(scrollBounds); 
    if (!view.getLocalVisibleRect(scrollBounds) || scrollBounds.width() < view.getWidth()) { 
     view.postDelayed(new Runnable() { 
     public void run() { 
      breadcrumbWrapper.smoothScrollTo(view.getLeft(), 0); 
     } 
     }, 100L); 
    } 
    } 

    void printDebug() { 
    System.out.println("** DEBUG ** | level: '" + currentLevel + "' | node: id='" + levelNodeIds.get(currentLevel) + "' name='" + levelNodeNames.get(currentLevel) + "' |"); 
    } 
} 
0

我知道这是相当古老的,但这似乎与任何地方发表这一点一样好。在那里有一个BreadcrumbsView via Github,似乎符合目的的需要。希望它能帮助其他人寻找类似的解决方案。