Can you use a WatchViewStub in a GridViewPager for Android Wear?

99封情书 提交于 2019-12-14 00:34:04

问题


I have a WatchViewStub that works fine on its own - it displays the correct layout on the appropriate square or round android wear emulator. But when I try and use the WatchViewStub in a GridViewPager it always displays the square (or rectangle) layout even on the round emulator. Is it possible to use the two together successfully?

Here are some code fragments:

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);

    setContentView(R.layout.activity_wear);

    GridViewPager pager = (GridViewPager) findViewById(R.id.activity_wear_pager);
    pager.setAdapter(new gridViewPagerAdapter());

    DotsPageIndicator dotsPageIndicator = (DotsPageIndicator) findViewById(R.id.activity_wear_page_indicator);
    dotsPageIndicator.setPager(pager);
}

Here's the gridViewPagerAdapter:

private class gridViewPagerAdapter extends GridPagerAdapter {
    @Override
    public int getColumnCount(int arg0) { return 2; }

    @Override
    public int getRowCount() { return 1; }

    @Override
    protected Object instantiateItem(ViewGroup container, int row, int col) {
        View view = null;

        if (col == 0) {
            view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.read_page_stub, container, false);
            WatchViewStub stub = (WatchViewStub) view.findViewById(R.id.read_page_stub);
            stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
                @Override
                public void onLayoutInflated(WatchViewStub stub) {
                }
            });
        }
        else {
            view = LayoutInflater.from(getApplicationContext()).inflate(R.layout.find_page_stub, container, false);
            WatchViewStub stub = (WatchViewStub) view.findViewById(R.id.find_page_stub);
            stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() {
                @Override
                public void onLayoutInflated(WatchViewStub stub) {
                }
            });
        }

        container.addView(view);
        return view;
    }

    @Override
    protected void destroyItem(ViewGroup container, int row, int col, Object view) {
        container.removeView((View)view);
    }

    @Override
    public boolean isViewFromObject(View view, Object object) {
        return view==object;
    }
}

Here is activity_wear.xml:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent" >

    <android.support.wearable.view.GridViewPager
        android:id="@+id/activity_wear_pager"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:keepScreenOn="true"/>

    <android.support.wearable.view.DotsPageIndicator
        android:id="@+id/activity_wear_page_indicator"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center_horizontal|bottom">
    </android.support.wearable.view.DotsPageIndicator>

</FrameLayout>

Here is read_page_stub.xml:

<?xml version="1.0" encoding="utf-8"?>
<android.support.wearable.view.WatchViewStub
    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/read_page_stub"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:rectLayout="@layout/read_page_rect"
    app:roundLayout="@layout/read_page_round"
    tools:context=".WearApplication"
    tools:deviceIds="wear">
</android.support.wearable.view.WatchViewStub>

Then I have two layouts with my views. They start with:

read_page_rect.xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WearApplication"
    tools:deviceIds="wear_square">

read_page_round.xml:

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/scroll"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    tools:context=".WearApplication"
    tools:deviceIds="wear_round">

I have the same type of layout setup for find_page_stub, find_page_rect, and find_page_round.


回答1:


If WatchViewStub doesn't show the round layout it means it doesn't receive the WindowInsets object properly. GridViewPager must be consuming it somewhere on the way.

You can try and fix it. The way to do this is (first some theory):

1) start by reading about View.dispatchApplyWindowInsets and View.onApplyWindowInsets

2) the way these two methods are tied in a View is this: dispatchApplyWindowInsets is called and checks if there is any listener; if yes, it delivers the WindowInsets to the listener only; if no, it delivers the WindowInsets to onApplyWindowInsets.

3) in a ViewGroup (and GridViewPager is a ViewGroup) it iterates over the children and checks if the insets were consumed; if yes, it stops delivering them;

4) at any point any View/ViewGroup can decide to stop delivering the WindowInsets; when it does, any children depending on it won't behave properly on round;

now some practice:

5) you can create a subclass of any view you have in your hierarchy; do this with GridViewPager and start experimenting with overriding dispatchApplyWindowInsets and onApplyWindowInsets. My guess is the first one should be enough.

6) in the override of dispatchApplyWindowInsets iterate over children and call dispatchApplyWindowInsets to every of them; this way WatchViewStub should receive unaltered WindowInsets with the previous isRound()->true method

7) finally, don't forget to call super.dispatchApplyWindowInsets(windowInsets); you want to let GridViewPager do what it needs with the insets.

Phew, pretty long, but should help you and also give you some understanding why things are happening the way are happening. I think we have a bug standing to fix this GridViewPager issue, so maybe after the next release you won't have to deal with this.




回答2:


As @gruszczy mentions, the GridViewPager consumes the WindowsInsets callbacks by default. The way to fix this is to manually set it to not do it by code:

mGridViewPager.setConsumeWindowInsets(false);

This method set an internal boolean attribute that is used on the dispatcher method of the insets. As can be seen here:

 public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) {
    insets = this.onApplyWindowInsets(insets);
    if(this.mOnApplyWindowInsetsListener != null) {
        this.mOnApplyWindowInsetsListener.onApplyWindowInsets(this, insets);
    }

    return this.mConsumeInsets?insets.consumeSystemWindowInsets():insets;
}

As a final note, this is on version 1.3.0 of the Support Wearable library. I'm not sure if this is included on previous versions...



来源:https://stackoverflow.com/questions/28975375/can-you-use-a-watchviewstub-in-a-gridviewpager-for-android-wear

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!