两种布局在Android Studio布局设计中都显示正常.
项目测试:
https://bitbucket.org/powder366/motoblack
我使用以下代码:
public class MyFragment extends Fragment { ... @Override public View onCreateView(LayoutInflater inflater,ViewGroup container,Bundle savedInstanceState) { View contentView = inflater.inflate(R.layout.my_fragment,container,false); ...
布局my_fragment:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/my_fragment" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" android:keepScreenOn="true" tools:context=".WearFragment"> <LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical"> <TextView android:id="@+id/text1" android:text="Hi1" android:layout_gravity="center_horizontal" style="@style/UnitsStyle"/> <TextView android:id="@+id/text2" android:text="Hi2" android:layout_gravity="center_horizontal" style="@style/BaseStyle"/> <TextView android:id="@+id/text3" android:text="Hi3" android:layout_gravity="center_horizontal" style="@style/UnitsStyle"/> </LinearLayout> </LinearLayout>
从以下地址拨打电话:
public class MenuAdapter extends FragmentGridPagerAdapter ... public MenuAdapter(Context context,FragmentManager fm,Handler handler) { super(fm); mContext = context; mHandler = handler; myFragment = new MyFragment(); } ... @Override public Fragment getFragment(int rowNum,int colNum) { Log.d(TAG,String.format("getFragment(%d,%d)",rowNum,colNum)); if(colNum == 0) { return myFragment; } if(colNum == 1) { final SecondFragment switchAction = SecondFragment.newInstance(mHandler); return switchAction; } return null; } ...
这是从:
public class WearActivity extends Activity { ... private GridViewPager gridViewPager; private MenuAdapter menuAdapter; @Override protected void onCreate(Bundle savedInstanceState) { Log.d(TAG,"Create(Wear)"); super.onCreate(savedInstanceState); setContentView(R.layout.wear_activity); final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { menuAdapter = new MenuAdapter(WearActivity.this,getFragmentManager(),mHandler); gridViewPager = (GridViewPager) findViewById(R.id.pager); gridViewPager.setAdapter(menuAdapter); } }); } ...
更新:
wear_activity.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/watch_view_stub" android:layout_width="match_parent" android:layout_height="match_parent" app:rectLayout="@layout/rect_activity" app:roundLayout="@layout/round_activity" tools:context=".WearActivity" tools:deviceIds="wear"> </android.support.wearable.view.WatchViewStub>
rect_activity.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" tools:deviceIds="wear_square"> <com.xyz.my.ScrollableGridViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true"/> </FrameLayout>
round_activity.xml
<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_gravity="center" tools:deviceIds="wear_round"> <com.xyz.my.ScrollableGridViewPager xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/pager" android:layout_width="match_parent" android:layout_height="match_parent" android:keepScreenOn="true"/> </FrameLayout>
额外信息:
public class ScrollableGridViewPager extends GridViewPager { ...
解决方法
理由#1:
这个问题的真正原因是onLayoutInflated(WatchViewStub)方法在圆形设备上被调用两次.
当rect_activity.xml被夸大时,它首次被调用:
WearActivity$1.onLayoutInflated(WatchViewStub) line: 26 WatchViewStub.inflate() line: 133 WatchViewStub.onMeasure(int,int) line: 141 WatchViewStub(View).measure(int,int) line: 16648
但在此之后,当调度onApplyWindowInsets(WindowInsets)时,第二次调用此方法是使用新膨胀的round_activity.xml完成的:
WearActivity$1.onLayoutInflated(WatchViewStub) line: 26 WatchViewStub.inflate() line: 133 WatchViewStub.onApplyWindowInsets(WindowInsets) line: 112 WatchViewStub(View).dispatchApplyWindowInsets(WindowInsets) line: 6051 WatchViewStub(ViewGroup).dispatchApplyWindowInsets(WindowInsets) line: 5435 SwipeDismissLayout(ViewGroup).dispatchApplyWindowInsets(WindowInsets) line: 5439 PhoneWindow$DecorView(ViewGroup).dispatchApplyWindowInsets(WindowInsets) line: 5439 ViewRootImpl.dispatchApplyInsets(View) line: 1170
我不知道这个问题是仅在模拟器上还是在真实设备上发生,但我认为这应该被报告为wearable-support-lib中的一个错误(在WatchViewStub组件中是准确的).任何地方都没有记录这种行为.
理由#2(#1的视觉后果):
上面的问题听起来应该什么都不做……新布局被夸大(所以旧的布局被删除),将创建新的MenuAdapter(旧的将不再使用,所以谁关心),这个新创建应将MenuAdapter设置为新GridViewPager中的适配器.一切都应该“重置”所以它应该仍然可以正常工作(除了由于布局膨胀两次而不是一次膨胀的性能问题).
不完全是……因为这是GridViewPager的棘手部分.
我不知道GridViewPager和FragmentGridPagerAdapter的确切源代码,但它似乎与ViewPager和FragmentPagerAdapter代码类似. FragmentPagerAdapter将新创建的片段添加到FragmentManager,其中包含由ViewPager的id和给定子片段的位置组成的特殊标记:
122 private static String More ...makeFragmentName(int viewId,int index) { 123 return "android:switcher:" + viewId + ":" + index; 124 }
将片段添加到FragmentManager(在当前活动中)后,将来可以通过此标记名称引用它.
真正的问题是由onLayoutInflated(WatchViewStub)方法被调用两次这一事实引起的.第一个片段在第一个MenuAdapter中创建,并添加到ID为R.id.pager的容器中(来自rect_activity.xml).然后对round_activity.xml进行膨胀,并调用对onLayoutInflated(WatchViewStub)的第二次调用 – 在新的MenuAdapter中创建新片段,并将其添加到具有相同id的新膨胀的GridViewPager:R.id.pager.所以第一个片段和第二个片段想要在FragmentManager中拥有完全相同的标签.
在标准的FragmentPagerAdapter中,如果FragmentManager中已经存在具有给定标记的片段,则它将再次附加到它的前一个父级.你可以在这里看到源代码:
50 @Override 51 public Object More ...instantiateItem(View container,int position) { 52 if (mCurTransaction == null) { 53 mCurTransaction = mFragmentManager.beginTransaction(); 54 } 55 56 // Do we already have this fragment? 57 String name = makeFragmentName(container.getId(),position); 58 Fragment fragment = mFragmentManager.findFragmentByTag(name); 59 if (fragment != null) { 60 if (DEBUG) Log.v(TAG,"Attaching item #" + position + ": f=" + fragment); 61 mCurTransaction.attach(fragment); 62 } else { 63 fragment = getItem(position); 64 if (DEBUG) Log.v(TAG,"Adding item #" + position + ": f=" + fragment); 65 mCurTransaction.add(container.getId(),fragment,66 makeFragmentName(container.getId(),position)); 67 } 68 if (fragment != mCurrentPrimaryItem) { 69 fragment.setMenuVisibility(false); 70 } 71 72 return fragment; 73 }
所以可能情况类似,第一个片段被重用,它被添加到第一个带有ID为R.id.pager的GridViewPager中 – 但是这个父节点不再存在,所以片段不能附加在任何地方(并显示).这是一个实现的事情,在一个Activity中只有一个具有给定id的ViewPager父类.
对于另一个实验,我为GridViewPagers设置了不同的id.一个用rect_activity.xml有id R.id.pager1,另一个在round_activity.xml有`R.id.pager2′.
final WatchViewStub stub = (WatchViewStub) findViewById(R.id.watch_view_stub); stub.setOnLayoutInflatedListener(new WatchViewStub.OnLayoutInflatedListener() { @Override public void onLayoutInflated(WatchViewStub stub) { menuAdapter = new MenuAdapter(WearActivity.this,getFragmentManager()); GridViewPager gridViewPager1 = (GridViewPager) findViewById(R.id.pager1); if(gridViewPager1!=null) { // rect_activity gridViewPager1.setAdapter(menuAdapter); } GridViewPager gridViewPager2 = (GridViewPager) findViewById(R.id.pager2); if(gridViewPager2!=null) { // round_activity gridViewPager2.setAdapter(menuAdapter); } } });
在第一次传递中,仅找到gridViewPager1并且仅设置其适配器.类似于第二次传递 – 仅设置了gridViewPager2的适配器.
因为GridViewPagers具有不同的id,所以片段标记中没有冲突,因此最终结果是预期的.
但这只是为了证明上面描述的理论:)
解:
WatchViewStub用于为rect和round屏幕提供不同的布局.我可以看到你对两种形状使用完全相同的布局.你可以摆脱WatchViewStub,只需这样做:
public class WearActivity extends Activity { private GridViewPager gridViewPager; private MenuAdapter menuAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.rect_activity); menuAdapter = new MenuAdapter(WearActivity.this,getFragmentManager()); gridViewPager = (GridViewPager) findViewById(R.id.pager); gridViewPager.setAdapter(menuAdapter); } }
这将使您的示例在不使用WatchViewStub的情况下完美运行.