Android材质设计-如何在工具栏中放置面包屑(导航)? [英] Android material design - How do I place a breadcrumb (navigation) in the toolbar?

查看:77
本文介绍了Android材质设计-如何在工具栏中放置面包屑(导航)?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图弄清楚如何在我的android应用程序的(材质设计)工具栏中创建面包屑.

I am trying to figure out how to create a breadcrumb in my android app's (material design) toolbar.

这可以在最新的Dropbox android应用程序中看到,该应用程序中的面包屑用于显示文件的导航.

This can be seen in the latest Dropbox android application, in which the breadcrumb is used to display the navigation of the files.

我还找到了一张图片(是我从另一个类似的问题),可以在此处查看:

I have also found an image (which I took from another similar question), which can be seen here:

您能指导我如何做到这一点吗?

Can you guide me on how I can do this?

推荐答案

我为一个应用程序创建了一个可行的示例,以为我会分享,因为它变得比需要大声笑起来更加混乱.也许可以为一些开发人员节省很多本不应该需要的工作:)

I created a working example of this for an app, thought I would share because it became more confusing than it needed to be lol. Maybe it could save some devs a lot of effort that should not be needed :)

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

Add a HorizontalScrollView to your AppBarLayout (layout/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 .您将为每个膨胀相同的布局. ( layout/breadcrumb_text )

Create a LinearLayout that will be used for each 'breadcrumb'. You will inflate the same layout for each. (layout/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%复制粘贴,因为您的应用程序会有所不同,具体取决于将添加面包屑的活动和设置.如果您还需要其他任何方法来使此工作正常,请告诉我.

ExampleBreadcrumbs that demonstrates the basic create/updates/scroll to methods that you could easily add to your app flow. Is not 100% copy paste because your app will be a little different depending on what activity and setup your breadcrumbs would be added to. If you need anything else to get this working... let me know.

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) + "' |");
  }
}

这篇关于Android材质设计-如何在工具栏中放置面包屑(导航)?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆