本文是在对大神文章的理解基础上写的,算是对大神的文章做注解吧!大神文章地址:原文地址
ViewPager用的很多,比如广告条等等,可是高度却不能自适应内容,总是会占满全屏,即使设置android:height=”wrap_content”也是没有用的。后来通过网上搜索,发现了几个思路:
一、使用LinearLayout布局,利用其使用weight来自动调整ViewPager的高度;
二、使用高度固定写死的方法来解决;
三、通过自定义ViewPager,重写其onMeasure方法;
四、最后是通过代码来动态的获取ViewPager的子View高度,然后将这个高度赋值给ViewPager。
我们现在就来说说每个方法的使用:
首先第一个,适用于父布局占据整个屏幕的时候,如图:
使用方法(代码和效果图片不一样,只是这里举例说明使用方法):
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<android.support.v4.view.ViewPager
android:id="@+id/pager"
android:layout_width="fill_parent"
android:layout_height="0dp"
android:layout_weight="1.0" />
<ImageView
android:id="@+id/ivCursor"
android:layout_width="60dp"
android:layout_height="5dp"
android:scaleType="fitCenter"
android:src="@drawable/cursor" />
<LinearLayout
android:id="@+id/tabs"
android:layout_width="fill_parent"
android:layout_height="wrap_content" />
LinearLayout>
第二种、使用高度固定写死的方法来解决。这种情况需要使用的ViewPager里面的内容全部固定尺寸,不需要随着设备屏幕的变变化而变化,所以屏幕适配就不达标。具体使用情况可以考虑定制设备的项目,比如银行的交互式平板,设备提供商软件部分就可以这么干,因为只有这一种设备来使用程序。
第三种情况就是通过自定义ViewPager,重写其onMeasure方法。适用于ViewPager的子View高度一定,比如最大化或者固定尺寸,使用后效果如上面地图效果。但是这种方法也有局限性,不良效果如图片:
这里ViewPager里面包裹的Fragment使用了Gridview且Gridview高度自适应,在onMeasure中返回childView的高度就只有Gridview默认的一排内容高度。
import android.content.Context;
import android.support.v4.view.ViewPager;
import android.util.AttributeSet;
import android.view.View;
public class WrapContentHeightViewPager extends ViewPager {
public WrapContentHeightViewPager(Context context) {
super(context);
}
public WrapContentHeightViewPager(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
//下面遍历所有child的高度
for (int i = 0; i < getChildCount(); i++) {
View child = getChildAt(i);
child.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
int h = child.getMeasuredHeight();
if (h > height) //采用最大的view的高度。
height = h;
}
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
最后一种方法,使用代码动态的获取Fragment高度,然后将高度赋值给ViewPager。先上代码然后讲解:
/**
* 设置ViewPager的自适应
* @param childViewHeight
*/
private void setViewPagerWrapContentHeight(int childViewHeight)
{
int viewPagerIndex = main.indexOfChild(viewPager);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, childViewHeight );//这里设置params的高度。
main.removeView(viewPager);
main.addView(viewPager, viewPagerIndex , params);//使用这个params
}
mian代表父布局,这里要注意,如果父布局是LinearLayout或者其它布局,那么main声明的时候就是这个布局,不能声明为View或者其它布局,否则这里容易造成类型转换异常。这一句代码也很简单,就是获取ViewPager在父布局的子View中排行老几?
LinearLayout.LayoutParams这个参数根据父布局来定,切忌不要用了父布局的子类或者与父布局无关的类(即只能用父布局本身或者其父类),否则这里设置高度的时候会造成类型转换异常。这一句代码就是设置一个属性宽度最大、高度为给定的childViewHeight的一个属性params。
如果上面两句代码代码照做了,后面就没有问题了,代码执行逻辑是删除ViewPager,然后马上在之前ViewPager的位置加上ViewPager,且对其属性修改为我们刚刚设置的属性。
Tip:这里我也不明白为什么ViewPager的属性是LinearLayout.LayoutParams,因为viewgroup的属性没有带参数的方法,或许LinearLayout是ViewPager的父类或者是祖宗类,这里求知道因由的大神在评论处解释一下,谢谢!
setViewPagerWrapContentHeight这个方法在什么地方调用我就不说了,最后唠叨一点,子View高度怎么取?我是在ViewPager包裹的Fragment的OnCreateView方法里面使用handler传回来的。这里要注意,直接在OnCreateView方法方法里面取view.getHeight()只能得到0,这里正确打开姿势是这样的:
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
View layout = inflater.inflate(R.layout.emoji_icon_fragment, container, false);
mGridView = (GridView) layout.findViewById(R.id.gview);
EmojiFragmentAdapter adapter = new EmojiFragmentAdapter(getActivity(), bitmapData);
mGridView.setAdapter(adapter);
mGridView.setOnItemClickListener(this);
mGridView.post(new Runnable() {
@Override
public void run() {
handler.sendEmptyMessage(mGridView.getHeight());
}
});
return layout;
}
参考文章:http://my.oschina.net/lifj/blog/283346