android AppBarLayout में टूलबार स्क्रॉल करने योग्य है हालांकि RecyclerView में स्क्रॉल करने के लिए पर्याप्त सामग्री नहीं है




android-xml android-coordinatorlayout (7)

धन्यवाद, मैंने रीसाइक्लिंग setNestedScrollingEnabled() का एक कस्टम क्लास बनाया है लेकिन कुंजी अभी भी setNestedScrollingEnabled() का उपयोग कर setNestedScrollingEnabled() । यह मेरी तरफ ठीक काम किया।

public class RecyclerViewCustom extends RecyclerView implements ViewTreeObserver.OnGlobalLayoutListener
{
    public RecyclerViewCustom(Context context)
    {
        super(context);
    }

    public RecyclerViewCustom(Context context, @Nullable AttributeSet attrs)
    {
        super(context, attrs);
    }

    public RecyclerViewCustom(Context context, @Nullable AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    /**
     *  This supports scrolling when using RecyclerView with AppbarLayout
     *  Basically RecyclerView should not be scrollable when there's no data or the last item is visible
     *
     *  Call this method after Adapter#updateData() get called
     */
    public void addOnGlobalLayoutListener()
    {
        this.getViewTreeObserver().addOnGlobalLayoutListener(this);
    }

    @Override
    public void onGlobalLayout()
    {
        // If the last item is visible or there's no data, the RecyclerView should not be scrollable
        RecyclerView.LayoutManager layoutManager = getLayoutManager();
        final RecyclerView.Adapter adapter = getAdapter();
        if (adapter == null || adapter.getItemCount() <= 0 || layoutManager == null)
        {
            setNestedScrollingEnabled(false);
        }
        else
        {
            int lastVisibleItemPosition = ((LinearLayoutManager) layoutManager).findLastCompletelyVisibleItemPosition();
            boolean isLastItemVisible = lastVisibleItemPosition == adapter.getItemCount() - 1;
            setNestedScrollingEnabled(!isLastItemVisible);
        }

        unregisterGlobalLayoutListener();
    }

    private void unregisterGlobalLayoutListener()
    {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN)
        {
            getViewTreeObserver().removeOnGlobalLayoutListener(this);
        }
        else
        {
            getViewTreeObserver().removeGlobalOnLayoutListener(this);
        }
    }
}

क्या यह वास्तव में इरादा है कि ऐपबारलाउट में टूलबार स्क्रॉल करने योग्य है हालांकि "appbar_scrolling_view_behavior" के साथ मुख्य कंटेनर में वास्तव में स्क्रॉल करने के लिए पर्याप्त सामग्री नहीं है?

मैंने अब तक परीक्षण किया है:
जब मैं नेस्टेडस्क्रोल व्यू ("wrap_content" विशेषता के साथ) मुख्य कंटेनर और टेक्स्ट व्यू के रूप में बच्चे के रूप में उपयोग करता हूं, तो AppBarLayout ठीक से काम करता है और स्क्रॉल नहीं करता है।

हालांकि, जब मैं केवल कुछ प्रविष्टियों और "wrap_content" विशेषता ("स्क्रॉल करने की कोई आवश्यकता नहीं है) के साथ एक RecyclerView का उपयोग करता हूं, तो AppBarLayout में टूलबार स्क्रॉल करने योग्य है भले ही RecyclerView को स्क्रॉल ईवेंट प्राप्त नहीं होता है (ऑनस्क्रॉल चेंजलिस्टर के साथ परीक्षण किया जाता है) )।

मेरा लेआउट कोड यहां दिया गया है:

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        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="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="scroll|enterAlways"
            app:theme="@style/ToolbarStyle" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>

निम्न प्रभाव के साथ टूलबार स्क्रॉल करने योग्य है हालांकि यह आवश्यक नहीं है:

मुझे यह जांचकर इसका निपटारा करने का एक तरीका भी मिला है कि क्या सभी रीसाइक्लिंग व्यू आइटम दिखाई दे रहे हैं और RecyclerView की setNestedScrollingEnabled () विधि का उपयोग कर रहे हैं।
फिर भी, यह मेरे लिए इरादे के रूप में एक बग की तरह लग रहा है। कोई राय? : डी

संपादित करें # 1:

उन लोगों के लिए जो मेरे वर्तमान समाधान में दिलचस्पी रखते हैं, मुझे लेआउटमैनेजर के कारण 5 एमएस देरी के साथ हैंडलर की पोस्टडेलेड () विधि में setNestedScrollingEnabled () तर्क को रखना था जो हमेशा वापस लौटाता था चाहे पहली और आखिरी वस्तु दिखाई दे।
मैं इस कोड का उपयोग ऑनस्टार्ट () विधि में करता हूं (मेरे रीसाइक्लर व्यू को प्रारंभ करने के बाद) और रीसाइक्लिंग व्यू के एक सामग्री परिवर्तन के बाद हर बार होता है।

final LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager();
new Handler().postDelayed(new Runnable() {
    @Override
    public void run() {
        //no items in the RecyclerView
        if (mRecyclerView.getAdapter().getItemCount() == 0)
            mRecyclerView.setNestedScrollingEnabled(false);
        //if the first and the last item is visible
        else if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0
                && layoutManager.findLastCompletelyVisibleItemPosition() == mRecyclerView.getAdapter().getItemCount() - 1)
            mRecyclerView.setNestedScrollingEnabled(false);
        else
            mRecyclerView.setNestedScrollingEnabled(true);
    }
}, 5);

संपादित करें # 2:

मैंने अभी एक नए ऐप के साथ खेला है और ऐसा लगता है कि यह (अनपेक्षित) व्यवहार समर्थन पुस्तकालय संस्करण 23.3.0 (या इससे पहले भी) में तय किया गया है। इस प्रकार, अब कामकाज की कोई ज़रूरत नहीं है!


मैंने इसे अपने व्यवहार वर्ग का उपयोग करके कार्यान्वित किया है जो ऐपबारलाउट से जुड़ा हो सकता है:

public class CustomAppBarLayoutBehavior extends AppBarLayout.Behavior {

private RecyclerView recyclerView;
private int additionalHeight;

public CustomAppBarLayoutBehavior(RecyclerView recyclerView, int additionalHeight) {
    this.recyclerView = recyclerView;
    this.additionalHeight = additionalHeight;
}

public boolean isRecyclerViewScrollable(RecyclerView recyclerView) {
    return recyclerView.computeHorizontalScrollRange() > recyclerView.getWidth() || recyclerView.computeVerticalScrollRange() > (recyclerView.getHeight() - additionalHeight);
}

@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes) {
    if (isRecyclerViewScrollable(mRecyclerView)) {
        return super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes);
    }
    return false;
}

}

और नीचे यह व्यवहार है कि इस व्यवहार को कैसे सेट करें:

final View appBarLayout = ((DrawerActivity) getActivity()).getAppBarLayoutView();
CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) appBarLayout.getLayoutParams();
layoutParams.setBehavior(new AppBarLayoutNoEmptyScrollBehavior(recyclerView, getResources().getDimensionPixelSize(R.dimen.control_bar_height)));

मैंने सुझाव दिया कि आप इस नमूना को आजमाएं कि समर्थन पुस्तकालय तत्वों के समर्थन के लिए।

नमूना में आपके लेआउट की तरह यह एक लेआउट।

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/main_content"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appbar"
        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:popupTheme="@style/ThemeOverlay.AppCompat.Light"
            app:layout_scrollFlags="scroll|enterAlways" />

        <android.support.design.widget.TabLayout
            android:id="@+id/tabs"
            android:layout_width="match_parent"
            android:layout_height="wrap_content" />

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

    <android.support.v4.view.ViewPager
        android:id="@+id/viewpager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />

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

LayoutManager में ऐसा कुछ वांछित व्यवहार के परिणामस्वरूप लगता है:

@Override
public boolean canScrollVertically() {
    int firstCompletelyVisibleItemPosition = findFirstCompletelyVisibleItemPosition();
    if (firstCompletelyVisibleItemPosition == RecyclerView.NO_POSITION) return false;

    int lastCompletelyVisibleItemPosition = findLastCompletelyVisibleItemPosition();
    if (lastCompletelyVisibleItemPosition == RecyclerView.NO_POSITION) return false;

    if (firstCompletelyVisibleItemPosition == 0 &&
            lastCompletelyVisibleItemPosition == getItemCount() - 1)
        return false;

    return super.canScrollVertically();
}

canScrollVertically() लिए प्रलेखन कहता है:

/**
 * Query if vertical scrolling is currently supported. The default implementation
 * returns false.
 *
 * @return True if this LayoutManager can scroll the current contents vertically
 */

" वर्तमान सामग्री को लंबवत स्क्रॉल कर सकते हैं" के शब्द पर ध्यान दें, जिसका मेरा मानना ​​है कि वर्तमान स्थिति वापसी मूल्य से प्रतिबिंबित होना चाहिए।

हालांकि, यह v7 recyclerview लाइब्रेरी (23.1.1) के माध्यम से प्रदान किए गए किसी भी LayoutManager द्वारा नहीं किया जाता है, जो मुझे कुछ हद तक संकोच करता है कि यह सही समाधान है या नहीं; इससे इस प्रश्न में चर्चा की गई अन्य स्थितियों में अवांछित प्रभाव हो सकते हैं।


2 संपादित करें:

यह सुनिश्चित करने का एकमात्र तरीका है कि टूलबार स्क्रॉल करने योग्य नहीं है जब RecyclerView स्क्रॉल करने योग्य नहीं है सेटस्क्रॉलफ्लैग प्रोग्रामेटिक रूप से सेट करना है, जिसे जांचना आवश्यक है कि RecyclerView स्क्रॉल करने योग्य है या नहीं। एडाप्टर संशोधित होने पर हर बार यह जांच की जानी चाहिए।

गतिविधि के साथ संवाद करने के लिए इंटरफ़ेस:

public interface LayoutController {
    void enableScroll();
    void disableScroll();
}

मुख्य गतिविधि:

public class MainActivity extends AppCompatActivity implements 
    LayoutController {

    private CollapsingToolbarLayout collapsingToolbarLayout;

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

        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

        collapsingToolbarLayout = 
              (CollapsingToolbarLayout) findViewById(R.id.collapsing_toolbar);

        final FragmentManager manager = getSupportFragmentManager();
        final Fragment fragment = new CheeseListFragment();
        manager.beginTransaction()
                .replace(R.id.root_content, fragment)
                .commit();
    }

    @Override
    public void enableScroll() {
        final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams)
                                  collapsingToolbarLayout.getLayoutParams();
        params.setScrollFlags(
                AppBarLayout.LayoutParams.SCROLL_FLAG_SCROLL 
                | AppBarLayout.LayoutParams.SCROLL_FLAG_ENTER_ALWAYS
        );
        collapsingToolbarLayout.setLayoutParams(params);
    }

    @Override
    public void disableScroll() {
        final AppBarLayout.LayoutParams params = (AppBarLayout.LayoutParams)
                                  collapsingToolbarLayout.getLayoutParams();
        params.setScrollFlags(0);
        collapsingToolbarLayout.setLayoutParams(params);
    }
}

activity_main.xml:

<android.support.v4.widget.DrawerLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/drawer_layout"
    android:layout_height="match_parent"
    android:layout_width="match_parent"
    android:fitsSystemWindows="true">

    <android.support.design.widget.CoordinatorLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:id="@+id/main_content"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

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

            <android.support.design.widget.CollapsingToolbarLayout
                android:id="@+id/collapsing_toolbar"
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:fitsSystemWindows="true"
                app:contentScrim="?attr/colorPrimary">

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

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

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

        <FrameLayout
            android:id="@+id/root_content"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_gravity="fill_vertical"
            app:layout_behavior="@string/appbar_scrolling_view_behavior"/>

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

</android.support.v4.widget.DrawerLayout>

टेस्ट फ्रैगमेंट:

public class CheeseListFragment extends Fragment {

    private static final int DOWN = 1;
    private static final int UP = 0;

    private LayoutController controller;
    private RecyclerView rv;

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);

        try {
            controller = (MainActivity) getActivity();
        } catch (ClassCastException e) {
            throw new RuntimeException(getActivity().getLocalClassName()
                    + "must implement controller.", e);
        }
    }

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
        rv = (RecyclerView) inflater.inflate(
                R.layout.fragment_cheese_list, container, false);
        setupRecyclerView(rv);

        // Find out if RecyclerView are scrollable, delay required
        final Handler handler = new Handler();
        handler.postDelayed(new Runnable() {
            @Override
            public void run() {
                if (rv.canScrollVertically(DOWN) || rv.canScrollVertically(UP)) {
                    controller.enableScroll();
                } else {
                    controller.disableScroll();
                }
            }
        }, 100);

        return rv;
    }

    private void setupRecyclerView(RecyclerView recyclerView) {
        final LinearLayoutManager layoutManager = new LinearLayoutManager(recyclerView.getContext());

        recyclerView.setLayoutManager(layoutManager);

        final SimpleStringRecyclerViewAdapter adapter =
                new SimpleStringRecyclerViewAdapter(
                        getActivity(),
                        // Test ToolBar scroll
                        getRandomList(/* with enough items to scroll */)
                        // Test ToolBar pin
                        getRandomList(/* with only 3 items*/)
                );

        recyclerView.setAdapter(adapter);
    }
}

सूत्रों का कहना है:

संपादित करें:

व्यवहार को नियंत्रित करने के लिए आपको CollapsingToolbarLayout को हटा देना चाहिए।

ऐपबारलाउट पर सीधे टूलबार जोड़ना आपको एंटरअलेज़ तक पहुंचने और बाहर निकलने के लिए उपयोग नहीं करता है, लेकिन स्क्रॉल झंडे से बाहर निकलने के लिए अलग-अलग तत्वों पर प्रतिक्रिया नहीं दी जाती है। [...] सेटअप CollapsingToolbarLayout के ऐप का उपयोग करता है: layout_collapseMode = "पिन" यह सुनिश्चित करने के लिए कि टूलबार स्वयं स्क्रीन के शीर्ष पर पिन हो जाता है जबकि दृश्य ढहता है। http://android-developers.blogspot.com.tr/2015/05/android-design-support-library.html

<android.support.design.widget.CollapsingToolbarLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        app:layout_scrollFlags="scroll|exitUntilCollapsed">

    <android.support.v7.widget.Toolbar
        android:id="@+id/drawer_toolbar"
        android:layout_width="match_parent"
        android:layout_height="?attr/actionBarSize"
        app:layout_collapseMode="pin"/>

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

जोड़ना

app:layout_collapseMode="pin"

एक्सएमएल में अपने टूलबार में।

    <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:layout_collapseMode="pin"
        app:theme="@style/ToolbarStyle" />

तो, उचित क्रेडिट, इस जवाब ने लगभग मेरे लिए इसे हल किया https://.com/a/32923226/5050087 । लेकिन चूंकि यह टूलबार नहीं दिखा रहा था जब आपके पास वास्तव में एक स्क्रोल करने योग्य रीसाइक्लिंगव्यू था और इसकी आखिरी वस्तु दिखाई दे रही थी (यह पहली स्क्रॉल पर टूलबार नहीं दिखाएगी), मैंने इसे संशोधित करने और इसे एक आसान कार्यान्वयन और गतिशील के लिए अनुकूलित करने का निर्णय लिया एडेप्टर।

सबसे पहले, आपको अपने ऐपबार के लिए एक कस्टम लेआउट व्यवहार बनाना होगा:

public class ToolbarBehavior extends AppBarLayout.Behavior{

private boolean scrollableRecyclerView = false;
private int count;

public ToolbarBehavior() {
}

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

@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, AppBarLayout child, MotionEvent ev) {
    return scrollableRecyclerView && super.onInterceptTouchEvent(parent, child, ev);
}

@Override
public boolean onStartNestedScroll(CoordinatorLayout parent, AppBarLayout child, View directTargetChild, View target, int nestedScrollAxes, int type) {
    updatedScrollable(directTargetChild);
    return scrollableRecyclerView && super.onStartNestedScroll(parent, child, directTargetChild, target, nestedScrollAxes, type);
}

@Override
public boolean onNestedFling(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target, float velocityX, float velocityY, boolean consumed) {
    return scrollableRecyclerView && super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
}

private void updatedScrollable(View directTargetChild) {
    if (directTargetChild instanceof RecyclerView) {
        RecyclerView recyclerView = (RecyclerView) directTargetChild;
        RecyclerView.Adapter adapter = recyclerView.getAdapter();
        if (adapter != null) {
            if (adapter.getItemCount()!= count) {
                scrollableRecyclerView = false;
                count = adapter.getItemCount();
                RecyclerView.LayoutManager layoutManager = recyclerView.getLayoutManager();
                if (layoutManager != null) {
                    int lastVisibleItem = 0;
                    if (layoutManager instanceof LinearLayoutManager) {
                        LinearLayoutManager linearLayoutManager = (LinearLayoutManager) layoutManager;
                        lastVisibleItem = Math.abs(linearLayoutManager.findLastCompletelyVisibleItemPosition());
                    } else if (layoutManager instanceof StaggeredGridLayoutManager) {
                        StaggeredGridLayoutManager staggeredGridLayoutManager = (StaggeredGridLayoutManager) layoutManager;
                        int[] lastItems = staggeredGridLayoutManager.findLastCompletelyVisibleItemPositions(new int[staggeredGridLayoutManager.getSpanCount()]);
                        lastVisibleItem = Math.abs(lastItems[lastItems.length - 1]);
                    }
                    scrollableRecyclerView = lastVisibleItem < count - 1;
                }
            }
        }
    } else scrollableRecyclerView = true;
  }
}

फिर, आपको केवल अपनी लेआउट फ़ाइल में एपबार के लिए इस व्यवहार को परिभाषित करने की आवश्यकता है:

<android.support.design.widget.AppBarLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:fitsSystemWindows="true"
    app:layout_behavior="com.yourappname.whateverdir.ToolbarBehavior"
    >

मैंने स्क्रीन रोटेशन के लिए इसका परीक्षण नहीं किया है, इसलिए मुझे यह बताएं कि यह इस तरह काम करता है। मुझे लगता है कि यह काम करना चाहिए क्योंकि मुझे नहीं लगता कि घूर्णन होता है जब गिनती चर बचाया जाता है, लेकिन अगर यह नहीं करता है तो मुझे बताएं।

यह मेरे लिए सबसे आसान और स्वच्छ कार्यान्वयन था, इसका आनंद लें।


अपने Toolbar में scroll ध्वज को हटा दें, केवल enterAlways ध्वज छोड़कर आपको अपना प्रभाव प्राप्त करना चाहिए। पूर्णता के लिए, आपका लेआउट इस तरह दिखना चाहिए:

<android.support.design.widget.CoordinatorLayout 
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:id="@+id/coordinatorLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.design.widget.AppBarLayout
        android:id="@+id/appBarLayout"
        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="?attr/actionBarSize"
            android:background="?attr/colorPrimary"
            app:layout_scrollFlags="enterAlways"
            app:theme="@style/ToolbarStyle" />
    </android.support.design.widget.AppBarLayout>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/recycler"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        app:layout_behavior="@string/appbar_scrolling_view_behavior" />
</android.support.design.widget.CoordinatorLayout>






android-appbarlayout