2016-10-20 29 views
5

tôi đang cố gắng để đạt được một cái gì đó giống như https://material.google.com/components/bottom-navigation.html#bottom-navigation-behaviorAndroid Hỗ trợ thiết kế: BottomNavigationView

Nhưng quan điểm tái chế này được cất giấu bên dưới thanh công cụ và không có tác dụng là trên BottomNavigationView

Dưới đây là mã của tôi

activity_main.xml

<?xml version="1.0" encoding="utf-8"?> 
<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/activity_main" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context=".MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/app_bar_layout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> 


     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:layout_scrollFlags="scroll|enterAlways" 
      app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> 
    </android.support.design.widget.AppBarLayout> 


    <RelativeLayout 
     android:layout_width="match_parent" 
     android:layout_height="match_parent"> 


     <android.support.design.widget.BottomNavigationView 
      android:id="@+id/nm_bottom" 
      android:layout_width="match_parent" 
      android:layout_height="wrap_content" 
      android:layout_alignParentBottom="true" 
      android:background="@color/colorPrimaryDark" 
      android:foregroundTint="@color/colorAccent" 
      app:itemIconTint="@android:color/white" 
      app:itemTextColor="@android:color/white" 
      app:menu="@menu/nav_menu" /> 

     <android.support.v7.widget.RecyclerView 
      android:id="@+id/rv" 
      android:layout_width="match_parent" 
      android:layout_height="match_parent" 
      android:layout_above="@id/nm_bottom" 
      app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 
    </RelativeLayout> 

</android.support.design.widget.CoordinatorLayout> 

item.xml

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    android:layout_width="match_parent" 
    android:layout_height="wrap_content" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    android:padding="4dp"> 

    <android.support.v7.widget.CardView 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     app:cardElevation="2dp"> 

     <RelativeLayout 
      android:layout_width="fill_parent" 
      android:layout_height="?android:attr/listPreferredItemHeight" 
      android:padding="4dp"> 

      <ImageView 
       android:id="@+id/icon" 
       android:layout_width="wrap_content" 
       android:layout_height="fill_parent" 
       android:layout_alignParentBottom="true" 
       android:layout_alignParentTop="true" 
       android:layout_marginRight="6dip" 
       android:contentDescription="TODO" 
       android:src="@drawable/ic_storage" /> 

      <TextView 
       android:id="@+id/secondLine" 
       android:layout_width="fill_parent" 
       android:layout_height="26dip" 
       android:layout_alignParentBottom="true" 
       android:layout_alignParentRight="true" 
       android:layout_toRightOf="@id/icon" 
       android:ellipsize="marquee" 
       android:text="Description" 
       android:textSize="12sp" /> 

      <TextView 
       android:id="@+id/firstLine" 
       android:layout_width="fill_parent" 
       android:layout_height="wrap_content" 
       android:layout_above="@id/secondLine" 
       android:layout_alignParentRight="true" 
       android:layout_alignParentTop="true" 
       android:layout_alignWithParentIfMissing="true" 
       android:layout_toRightOf="@id/icon" 
       android:gravity="center_vertical" 
       android:text="Example application" 
       android:textSize="16sp" /> 

     </RelativeLayout> 
    </android.support.v7.widget.CardView> 
</FrameLayout> 




public class MainActivity extends AppCompatActivity implements BottomNavigationView.OnNavigationItemSelectedListener { 

      private static final Logger logger = Logger.getLogger(MainActivity.class.getSimpleName()); 

      private BottomNavigationView navigationView; 
      private RecyclerView mRecyclerView; 
      private MyAdapter mAdapter; 

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

      private void initViews() { 
       navigationView = (BottomNavigationView) findViewById(R.id.nm_bottom); 
       navigationView.setOnNavigationItemSelectedListener(this); 
       mRecyclerView = (RecyclerView) findViewById(R.id.rv); 

       // use this setting to improve performance if you know that changes 
       // in content do not change the layout size of the RecyclerView 
       mRecyclerView.setHasFixedSize(true); 

       // use a linear layout manager 
       LinearLayoutManager mLayoutManager = new LinearLayoutManager(this); 
       mRecyclerView.setLayoutManager(mLayoutManager); 

       // specify an adapter (see also next example) 
       List<String> myDataset = new ArrayList<>(); 
       for (int i = 0; i < 100; i++) { 
        myDataset.add("Index #" + i); 
       } 
       mAdapter = new MyAdapter(myDataset); 
       mRecyclerView.setAdapter(mAdapter); 
      } 

      @Override 
      public boolean onNavigationItemSelected(@NonNull MenuItem item) { 

       return false; 
      } 
     } 

     public class MyAdapter extends RecyclerView.Adapter<MyAdapter.ViewHolder> { 
      private List<String> mDataset; 

      // Provide a reference to the views for each data item 
      // Complex data items may need more than one view per item, and 
      // you provide access to all the views for a data item in a view holder 
      public class ViewHolder extends RecyclerView.ViewHolder { 
       // each data item is just a string in this case 
       public TextView txtHeader; 
       public TextView txtFooter; 

       public ViewHolder(View v) { 
        super(v); 
        txtHeader = (TextView) v.findViewById(R.id.firstLine); 
        txtFooter = (TextView) v.findViewById(R.id.secondLine); 
       } 
      } 

      public void add(int position, String item) { 
       mDataset.add(position, item); 
       notifyItemInserted(position); 
      } 

      public void remove(String item) { 
       int position = mDataset.indexOf(item); 
       mDataset.remove(position); 
       notifyItemRemoved(position); 
      } 

      // Provide a suitable constructor (depends on the kind of dataset) 
      public MyAdapter(List<String> myDataset) { 
       mDataset = myDataset; 
      } 

      // Create new views (invoked by the layout manager) 
      @Override 
      public MyAdapter.ViewHolder onCreateViewHolder(ViewGroup parent, 
                  int viewType) { 
       // create a new view 
       View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_recycler_view, parent, false); 
       // set the view's size, margins, paddings and layout parameters 
       ViewHolder vh = new ViewHolder(v); 
       return vh; 
      } 

      // Replace the contents of a view (invoked by the layout manager) 
      @Override 
      public void onBindViewHolder(ViewHolder holder, int position) { 
       // - get element from your dataset at this position 
       // - replace the contents of the view with that element 
       final String name = mDataset.get(position); 
       holder.txtHeader.setText(mDataset.get(position)); 
       holder.txtHeader.setOnClickListener(new View.OnClickListener() { 
        @Override 
        public void onClick(View v) { 
         remove(name); 
        } 
       }); 

       holder.txtFooter.setText("Footer: " + mDataset.get(position)); 

      } 

      // Return the size of your dataset (invoked by the layout manager) 
      @Override 
      public int getItemCount() { 
       return mDataset.size(); 
      } 

     } 
+0

Tôi đã cố gắng chạy mã của bạn, tất cả mọi thứ hoạt động tốt. Những gì bạn có nghĩa là "không có hiệu lực là trên BottomNavigationView"? Bạn có nghĩa là hiệu ứng cuộn như thanh công cụ? – Srijith

+0

có và không thông báo mục đầu tiên của RecyclerView là bên dưới thanh công cụ – sector11

+0

Tôi nghĩ rằng hành vi cuộn chưa có sẵn cho BottomNavigationView. Tuy nhiên bạn có thể thực hiện một hành vi tùy chỉnh. Về mục recyclerview đầu tiên, xem câu trả lời của tôi – Srijith

Trả lời

15

Edit: Đây là một mẫu đơn giản cho thấy làm thế nào để thực hiện di chuyển hành vi https://github.com/sjthn/BottomNavigationViewBehavior

Thay đổi XML của bạn như thế này:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:app="http://schemas.android.com/apk/res-auto" 
    xmlns:tools="http://schemas.android.com/tools" 
    android:id="@+id/activity_main" 
    android:layout_width="match_parent" 
    android:layout_height="match_parent" 
    android:fitsSystemWindows="true" 
    tools:context=".MainActivity"> 

    <android.support.design.widget.AppBarLayout 
     android:id="@+id/app_bar_layout" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"> 


     <android.support.v7.widget.Toolbar 
      android:id="@+id/toolbar" 
      android:layout_width="match_parent" 
      android:layout_height="?attr/actionBarSize" 
      android:background="?attr/colorPrimary" 
      app:layout_scrollFlags="scroll|enterAlways" 
      app:popupTheme="@style/ThemeOverlay.AppCompat.Light" 
      app:title="@string/app_name" /> 
    </android.support.design.widget.AppBarLayout> 

    <android.support.v7.widget.RecyclerView 
     android:id="@+id/rv" 
     android:layout_width="match_parent" 
     android:layout_height="match_parent" 
     app:layout_behavior="@string/appbar_scrolling_view_behavior" /> 

    <android.support.design.widget.BottomNavigationView 
     android:id="@+id/nm_bottom" 
     android:layout_width="match_parent" 
     android:layout_height="wrap_content" 
     android:background="@color/colorPrimaryDark" 
     android:foregroundTint="@color/colorAccent" 
     app:itemIconTint="@android:color/white" 
     app:itemTextColor="@android:color/white" 
     app:layout_anchor="@+id/rv" 
     app:layout_anchorGravity="bottom" 
     app:menu="@menu/nav_menu" /> 

</android.support.design.widget.CoordinatorLayout> 
+0

Cảm ơn bạn dude, tôi sai lầm hoàn toàn với layout_ anchor/gravity. – sector11

+0

Bạn đang phải cuộn 'RecyclerView' Ẩn' ActionBar' của nó nhưng không ẩn 'BottomNavigatioView', nó bị ẩn ở đó. –

+0

Layout_anchor và layout_anchorGravity có được sử dụng theo cách này không? Tôi đã từng thấy chúng được sử dụng với FAB –

1

Vì vậy, với sự trợ giúp từ @Srijith i am có thể để animate cách nó được đưa ra trong liên kết.

Một phần của câu trả lời này là

public class BottomNavigationBehavior<V extends View> extends VerticalScrollingBehavior<V> { 
    private static final Interpolator INTERPOLATOR = new LinearOutSlowInInterpolator(); 
    private int mBottomNavigationViewId; 
    private boolean hidden = false; 
    private ViewPropertyAnimatorCompat mTranslationAnimator; 
    private BottomNavigationView navigationView; 
    private View mTabsHolder; 

    public BottomNavigationBehavior() { 
     super(); 
    } 

    public BottomNavigationBehavior(Context context, AttributeSet attrs) { 
     super(context, attrs); 
     mBottomNavigationViewId = R.id.nm_bottom; 
    } 

    @Override 
    public boolean onLayoutChild(CoordinatorLayout parent, V child, int layoutDirection) { 
     boolean layoutChild = super.onLayoutChild(parent, child, layoutDirection); 
     if (navigationView == null && mBottomNavigationViewId != View.NO_ID) { 
      navigationView = findTabLayout(child); 
      getTabsHolder(); 
     } 
     return layoutChild; 
    } 

    private BottomNavigationView findTabLayout(View child) { 
     return (BottomNavigationView) child.findViewById(mBottomNavigationViewId); 
    } 

    @Override 
    public void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll) { 
    } 

    @Override 
    public void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection) { 
     handleDirection(child, scrollDirection); 
    } 

    private void handleDirection(V child, int scrollDirection) { 
     if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_DOWN && hidden) { 
      hidden = false; 
      animateOffset(child, 0); 
     } else if (scrollDirection == ScrollDirection.SCROLL_DIRECTION_UP && !hidden) { 
      hidden = true; 
      animateOffset(child, child.getHeight()); 
     } 
    } 

    @Override 
    protected boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection) { 
     handleDirection(child, scrollDirection); 
     return true; 
    } 

    private void animateOffset(final V child, final int offset) { 
     ensureOrCancelAnimator(child); 
     mTranslationAnimator.translationY(offset).start(); 
     animateTabsHolder(offset); 
    } 

    private void animateTabsHolder(int offset) { 
     if (mTabsHolder != null) { 
      offset = offset > 0 ? 0 : 1; 
      ViewCompat.animate(mTabsHolder).alpha(offset).setDuration(200).start(); 
     } 
    } 


    private void ensureOrCancelAnimator(V child) { 
     if (mTranslationAnimator == null) { 
      mTranslationAnimator = ViewCompat.animate(child); 
      mTranslationAnimator.setDuration(100); 
      mTranslationAnimator.setInterpolator(INTERPOLATOR); 
     } else { 
      mTranslationAnimator.cancel(); 
     } 
    } 

    private void getTabsHolder() { 
     if (navigationView != null) { 
      mTabsHolder = navigationView.getChildAt(0); 
     } 
    } 

    public static <V extends View> BottomNavigationBehavior<V> from(V view) { 
     ViewGroup.LayoutParams params = view.getLayoutParams(); 
     if (!(params instanceof CoordinatorLayout.LayoutParams)) { 
      throw new IllegalArgumentException("The view is not a child of CoordinatorLayout"); 
     } 
     CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params) 
       .getBehavior(); 
     if (!(behavior instanceof BottomNavigationBehavior)) { 
      throw new IllegalArgumentException(
        "The view is not associated with ottomNavigationBehavior"); 
     } 
     return (BottomNavigationBehavior<V>) behavior; 
    } 

    public void setTabLayoutId(@IdRes int tabId) { 
     this.mBottomNavigationViewId = tabId; 
    } 
} 

public abstract class VerticalScrollingBehavior<V extends View> extends CoordinatorLayout.Behavior<V> { 

    private int mTotalDyUnconsumed = 0; 
    private int mTotalDy = 0; 
    @ScrollDirection 
    private int mOverScrollDirection = ScrollDirection.SCROLL_NONE; 
    @ScrollDirection 
    private int mScrollDirection = ScrollDirection.SCROLL_NONE; 

    public VerticalScrollingBehavior(Context context, AttributeSet attrs) { 
     super(context, attrs); 
    } 

    public VerticalScrollingBehavior() { 
     super(); 
    } 

    @Retention(RetentionPolicy.SOURCE) 
    @IntDef({ScrollDirection.SCROLL_DIRECTION_UP, ScrollDirection.SCROLL_DIRECTION_DOWN}) 
    public @interface ScrollDirection { 
     int SCROLL_DIRECTION_UP = 1; 
     int SCROLL_DIRECTION_DOWN = -1; 
     int SCROLL_NONE = 0; 
    } 


    /* 
     @return Overscroll direction: SCROLL_DIRECTION_UP, CROLL_DIRECTION_DOWN, SCROLL_NONE 
    */ 
    @ScrollDirection 
    public int getOverScrollDirection() { 
     return mOverScrollDirection; 
    } 


    /** 
    * @return Scroll direction: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN, SCROLL_NONE 
    */ 

    @ScrollDirection 
    public int getScrollDirection() { 
     return mScrollDirection; 
    } 


    /** 
    * @param coordinatorLayout 
    * @param child 
    * @param direction   Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN 
    * @param currentOverScroll Unconsumed value, negative or positive based on the direction; 
    * @param totalOverScroll Cumulative value for current direction 
    */ 
    public abstract void onNestedVerticalOverScroll(CoordinatorLayout coordinatorLayout, V child, @ScrollDirection int direction, int currentOverScroll, int totalOverScroll); 

    /** 
    * @param scrollDirection Direction of the overscroll: SCROLL_DIRECTION_UP, SCROLL_DIRECTION_DOWN 
    */ 
    public abstract void onDirectionNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed, @ScrollDirection int scrollDirection); 

    @Override 
    public boolean onStartNestedScroll(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { 
     return (nestedScrollAxes & View.SCROLL_AXIS_VERTICAL) != 0; 
    } 

    @Override 
    public void onNestedScrollAccepted(CoordinatorLayout coordinatorLayout, V child, View directTargetChild, View target, int nestedScrollAxes) { 
     super.onNestedScrollAccepted(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes); 
    } 

    @Override 
    public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) { 
     super.onStopNestedScroll(coordinatorLayout, child, target); 
    } 

    @Override 
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed) { 
     super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed, dxUnconsumed, dyUnconsumed); 
     if (dyUnconsumed > 0 && mTotalDyUnconsumed < 0) { 
      mTotalDyUnconsumed = 0; 
      mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP; 
     } else if (dyUnconsumed < 0 && mTotalDyUnconsumed > 0) { 
      mTotalDyUnconsumed = 0; 
      mOverScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN; 
     } 
     mTotalDyUnconsumed += dyUnconsumed; 
     onNestedVerticalOverScroll(coordinatorLayout, child, mOverScrollDirection, dyConsumed, mTotalDyUnconsumed); 
    } 

    @Override 
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target, int dx, int dy, int[] consumed) { 
     super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed); 
     if (dy > 0 && mTotalDy < 0) { 
      mTotalDy = 0; 
      mScrollDirection = ScrollDirection.SCROLL_DIRECTION_UP; 
     } else if (dy < 0 && mTotalDy > 0) { 
      mTotalDy = 0; 
      mScrollDirection = ScrollDirection.SCROLL_DIRECTION_DOWN; 
     } 
     mTotalDy += dy; 
     onDirectionNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, mScrollDirection); 
    } 


    @Override 
    public boolean onNestedFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, boolean consumed) { 
     super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed); 
     mScrollDirection = velocityY > 0 ? ScrollDirection.SCROLL_DIRECTION_UP : ScrollDirection.SCROLL_DIRECTION_DOWN; 
     return onNestedDirectionFling(coordinatorLayout, child, target, velocityX, velocityY, mScrollDirection); 
    } 

    protected abstract boolean onNestedDirectionFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY, @ScrollDirection int scrollDirection); 

    @Override 
    public boolean onNestedPreFling(CoordinatorLayout coordinatorLayout, V child, View target, float velocityX, float velocityY) { 
     return super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY); 
    } 

    @Override 
    public WindowInsetsCompat onApplyWindowInsets(CoordinatorLayout coordinatorLayout, V child, WindowInsetsCompat insets) { 

     return super.onApplyWindowInsets(coordinatorLayout, child, insets); 
    } 

    @Override 
    public Parcelable onSaveInstanceState(CoordinatorLayout parent, V child) { 
     return super.onSaveInstanceState(parent, child); 
    } 

} 

Tất cả câu trả lời này đến từ anh chàng này: https://medium.com/@nullthemall/bottom-navigation-behavior-388b9b206667#.potyetdkb

Toàn bộ dự án nằm here

Các vấn đề liên quan