我已经关注了this和that的答案,我还找到了this链接。
我使用这些资源进行试验和错误。现在我的自定义
ViewPager
成功测量了其内容,但只显示了第一个。仅供参考,我的 ViewPager
拥有一些复杂的视图,例如 ExpendableListView
- 这就是为什么这些资源中的代码都不能完美运行,我需要自己修改代码。
我有4个片段(内容),所以我使用
pager.setOffscreenPageLimit(3);
这是我的习惯
ViewPager
:
public class CustomViewPager extends ViewPager{
public CustomViewPager (Context context) {
super(context);
}
public CustomViewPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
final View tab = getChildAt(0);
int width = getMeasuredWidth();
int tabHeight = tab.getMeasuredHeight();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
这是我的
CustomPagerTabStrip
:
int expandSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2,MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, expandSpec);
android.view.ViewGroup.LayoutParams params = getLayoutParams();
params.height = getMeasuredHeight();
这是我的 XML :
<RelativeLayout
android:id="@+id/relativePager"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.xxx.yyy.util.CustomViewPager
android:id="@+id/detailPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.xxx.yyy.util.CustomPagerTabStrip
android:id="@+id/detailTab"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#161C28"
android:textColor="#FFFFFF" />
</com.xxx.yyy.util.CustomViewPager>
</RelativeLayout>
示例案例:
如果第一个片段的高度为 100 像素,则所有其他片段将保持在 100 像素。 因此,如果第二个片段的高度为 130px,它将被剪切为 100px。
当我尝试调试时,当创建
onMeasure
时,我的CustomViewPager
上的Activity
总是调用4次,但它们都只读取第一个片段。之后,即使我从一个片段更改(向左/向右滑动)到另一个片段,onMeasure
永远不会再次被调用。
请帮助我,我花了很多时间来让这个东西工作。
如果您需要更多信息,请询问我,感谢您的宝贵时间。
它包括自定义滚动视图和自定义视图寻呼机。自定义视图分页器的目的是根据其子项的高度动态计算高度,其高度最初设置为包裹内容,滚动视图的目的是处理触摸事件,如果用户垂直滚动屏幕,则不会传递触摸甚至滚动,因此用户可以滚动页面。
自定义滚动视图
public class CustomScrollView extends ScrollView {
private GestureDetector mGestureDetector;
public CustomScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
mGestureDetector = new GestureDetector(context, new YScrollDetector());
setFadingEdgeLength(0);
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev)
&& mGestureDetector.onTouchEvent(ev);
}
// Return false if we're scrolling in the x direction
class YScrollDetector extends SimpleOnGestureListener {
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2,
float distanceX, float distanceY) {
return (Math.abs(distanceY) > Math.abs(distanceX));
}
}
}
自定义视图寻呼机
public class CustomPager extends ViewPager{
public CustomPager (Context context) {
super(context);
}
public CustomPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
final View tab = getChildAt(0);
int width = getMeasuredWidth();
int tabHeight = tab.getMeasuredHeight();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
int fragmentHeight = measureFragment(((Fragment) getAdapter().instantiateItem(this, getCurrentItem())).getView());
heightMeasureSpec = MeasureSpec.makeMeasureSpec(tabHeight + fragmentHeight + (int)TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, 50, getResources().getDisplayMetrics()), MeasureSpec.AT_MOST);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
public int measureFragment(View view) {
if (view == null)
return 0;
view.measure(0, 0);
return view.getMeasuredHeight();
}
}
布局文件
<com.example.demo2.activity.widget.CustomScrollView 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" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<TextView
style="@style/text"
android:text="Text 1" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 2" />
<com.example.demo2.activity.widget.CustomPager
android:id="@+id/myViewPager"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 4" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 5" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 6" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 7" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 8" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 9" />
<View style="@style/text_divider" />
<TextView
style="@style/text"
android:text="Text 10" />
</LinearLayout>
活动
public class MainActivity extends FragmentActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
MyPagerAdapter pageAdapter = new MyPagerAdapter(getSupportFragmentManager());
ViewPager pager = (ViewPager)findViewById(R.id.myViewPager);
pager.setAdapter(pageAdapter);
}
}
片段适配器
不同高度的片段被添加到viewpager,FragmentBlue,Green等只是用于添加到viewpager的片段,您可以使用自己的片段,要记住的一件事是它们的外部布局应该是相同的,在我的情况下,我使用了衬垫布局全部
public class MyPagerAdapter extends FragmentPagerAdapter {
private List<Fragment> fragments;
public MyPagerAdapter(FragmentManager fm) {
super(fm);
this.fragments = new ArrayList<Fragment>();
fragments.add(new FragmentBlue());
fragments.add(new FragmentGreen());
fragments.add(new FragmentPink());
fragments.add(new FragmentRed());
}
@Override
public Fragment getItem(int position) {
return fragments.get(position);
}
@Override
public int getCount() {
return fragments.size();
}
}
public CustomPager (Context context) {
super(context);
}
public CustomPager (Context context, AttributeSet attrs) {
super(context, attrs);
}
int getMeasureExactly(View child, int widthMeasureSpec) {
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int height = child.getMeasuredHeight();
return MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
}
@Override
public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
boolean wrapHeight = MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST;
final View tab = getChildAt(0);
if (tab == null) {
return;
}
int width = getMeasuredWidth();
if (wrapHeight) {
// Keep the current measured width.
widthMeasureSpec = MeasureSpec.makeMeasureSpec(width, MeasureSpec.EXACTLY);
}
Fragment fragment = ((Fragment) getAdapter().instantiateItem(this, getCurrentItem()));
heightMeasureSpec = getMeasureExactly(fragment.getView(), widthMeasureSpec);
//Log.i(Constants.TAG, "item :" + getCurrentItem() + "|height" + heightMeasureSpec);
// super has to be called again so the new specs are treated as
// exact measurements.
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
private fun updateViewPagerHeightForCurrentPage(position: Int) {
val viewPager = itemView.findViewById<ViewPager2>(R.id.vp_orders)
val recyclerView = viewPager.getChildAt(0) as? RecyclerView ?: return
val viewHolder = recyclerView.findViewHolderForAdapterPosition(position) ?: return
val itemView = viewHolder.itemView
itemView.measure(
View.MeasureSpec.makeMeasureSpec(recyclerView.width, View.MeasureSpec.EXACTLY),
View.MeasureSpec.UNSPECIFIED
)
val newHeight = itemView.measuredHeight
val layoutParams = viewPager.layoutParams
layoutParams.height = newHeight
viewPager.layoutParams = layoutParams
}
使用方法:
viewPager.registerOnPageChangeCallback(object : OnPageChangeCallback(){
override fun onPageSelected(position: Int) {
super.onPageSelected(position)
updateViewPagerHeightForCurrentPage(position)
}
})