ScrollView嵌套ViewPager,网络获取图片自适应高度

   最近项目接到个需求,需要在首页的活动页设置图片,图片要能够按照屏幕的宽度,自适应放大高度,达到可以滑动的效果,一开始想,这很简单嘛,无非就是根据需要下载的图片,和屏幕宽度,计算出图片放大的比率,再使用Scrollview嵌套viewpager就可以了,结果发现图片都显示不出来了,搜索资料后,发现scrollview需要设置 

android:fillViewport="true"  来填充scrollview。


但是又遇到了高度的问题,尝试使用这段代码来解决

 @Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int height = 0;
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){
        height = h;
    }
heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,MeasureSpec.EXACTLY);
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

这段代码的作用其实重写onMeasure方法,然后从所有被预加载的view里面,找出高度最大的一个view对象,把整个viewpager的高度设置为它,这就导致了一个问题,最大的图片设置,没有任何问题,但是稍微小一点图片,就会出现viewpager与scrollview之间有很大的空白部分,很影响美观,所以我们在滑动到viewpager的某个界面的时候,必须要重新给当前的view设置它的高度。


之后我又继续搜索解决办法,发现了 李志强老哥的办法 附上csdn链接 

http://blog.csdn.net/lzq520210/article/details/53197535

他的解决办法里面,自定义了一个resertHeight的方法,并且重写了onMeasure方法,因为我们知道,viewpager每次滑动到一个页面,onMeasure方法都会被多次调用,来测量本页面的宽度与高度,于是我们设置一个私有的heigh属性,来计算当前itemview的高度,并把它保存下来。

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mChildrenViews.size() > current) {
View child = mChildrenViews.get(current);
child.measure(widthMeasureSpec, MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
}

heightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}

使用一个hashmap,来对因view与position的关系

private HashMap<Integer, View> mChildrenViews = new LinkedHashMap<Integer, View>();

用一个方法,来保存它

public void setObjectForPosition(View view, int position) {
mChildrenViews.put(position, view);
}

接下来,在自定义的 resetHeight里面,对约束viewpager的LinearLayout设置它的高度

public void resetHeight(int current) {
this.current = current;
if (mChildrenViews.size() > current) {

LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
if (layoutParams == null) {
layoutParams = new LinearLayout.LayoutParams(
LayoutParams.MATCH_PARENT, height);
} else {
layoutParams.height = height;
}
setLayoutParams(layoutParams);
}
}


这样的话,linearlayout的高度,就与viewpgaer的一致了


接下来,我们设置预加载的页面个数为3个

pager.setOffscreenPageLimit(3);

因为我们知道,viewpager每次滑动到一个新界面,都会在 setOnPageChangeListener 这个监听里面 回调 onPageSelected 这个方法

于是我们在这里,重置当前页面的高度

pager.resetHeight(position);

此外,PagerAdapte在j将要改变的时候,会首先调用startUpdate(),这个方法,之后它会一次或者多次的调用instantiateItem()或者destroyItem(),

前者毫无疑问,是用来实例化当前的itemview的,后者是用来消灭当前的itemview的,至于逻辑的话,我不是很清楚,可能是起到消除旧的view,设置新的view的作用。这一点,如果有朋友知道的话,可以指出来。

所以,我们在instantiateItem()里面对view设置它的position

// 存放view与position的对应
pager.setObjectForPosition(currentView,position);

再测试,发现有的界面,viewpaer的宽度并没有全屏,于是我又在onMeasure方法里面,把传入的屏幕宽度数值,设置上去,这样的话,就可以了。


附上代码:

为itemview的imageview设置自适应宽度的bitmap.

这里我们使用的是ImageLoader,这个jar包,然后使用createScaledBitmap()进行伸缩变换,注意

不建议使用 createBitmap(),这个方法如果检测到生成的New Bitmap大小大于原Bitmap的话,就会报错。

private DisplayImageOptions options;

options = new DisplayImageOptions.Builder().showImageForEmptyUri(null)
.showImageOnFail(null).cacheInMemory(true).cacheOnDisc(true)
.resetViewBeforeLoading(true).build();

imageLoader.loadImage(imgURL, options,
new ImageLoadingListener() {

@Override
public void onLoadingStarted(String imageUri,
View view) {
// TODO Auto-generated method stub

}

@Override
public void onLoadingFailed(String imageUri,
View view, FailReason failReason) {
// TODO Auto-generated method stub

}

@TargetApi(19)
@SuppressLint("NewApi")
@Override
public void onLoadingComplete(String imageUri,
View view, Bitmap loadedImage) {
int bitmapWidth = loadedImage.getWidth();
int bitmapHeight = loadedImage.getHeight();
// 计算比率
WindowManager wm = (WindowManager) PosterActivity.this
.getSystemService(Context.WINDOW_SERVICE);
int screenWidth = wm.getDefaultDisplay()
.getWidth();
float xRate = (float) bitmapWidth
/ (float) screenWidth;
Bitmap newbm = Bitmap.createScaledBitmap(
loadedImage, screenWidth,
(int) (bitmapHeight / xRate), true);
currentView.setTag( (int) (bitmapHeight / xRate));
cache.imgPoster.setTag((int) (bitmapHeight / xRate));
cache.imgPoster.setImageBitmap(newbm);
}

@Override
public void onLoadingCancelled(String imageUri,
View view) {
// TODO Auto-generated method stub

}
});


自定义,重写后的onMeasure方法,这里我不但重新计算了高度,也计算了宽度,宽度就是获取到的屏幕宽度,传入到自定义的ViewPager的,这里就不赘述了.

@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (mChildrenViews.size() > current) {
View child = mChildrenViews.get(current);
child.measure(widthMeasureSpec,
MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED));
height = child.getMeasuredHeight();
}

heightMeasureSpec = MeasureSpec.makeMeasureSpec(height,
MeasureSpec.EXACTLY);
if ((int) getScreenWidth() > 0)
widthMeasureSpec = MeasureSpec.makeMeasureSpec(
(int) getScreenWidth(), MeasureSpec.EXACTLY);
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}


然后是resetHeight(),这没啥好说的

public void resetHeight(int current) {
this.current = current;
if (mChildrenViews.size() > current) {
LinearLayout.LayoutParams layoutParams = (LinearLayout.LayoutParams) getLayoutParams();
if (layoutParams == null) {
layoutParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT, height);
} else {
layoutParams.height = height;
}
setLayoutParams(layoutParams);
}
}


这里重写了onInterceptTouchEvent(),来解决ViewPager与ScrollView的滑动冲突问题,主要就是根据滑动的起,终点,计算出位移,进行判断的。

//全局变量

private float mDownX;
private float mDownY;

// 重写onInterceptTouchEvent方法

@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_DOWN:
mDownX = ev.getRawX();
mDownY = ev.getRawY();
break;


case MotionEvent.ACTION_MOVE:
float mMoveX = ev.getRawX();
float mMoveY = ev.getRawY();
float xDistance = Math.abs(mMoveX - mDownX);
float yDiatance = Math.abs(mMoveY - mDownY);
if (xDistance > 50)
getParent().requestDisallowInterceptTouchEvent(true);
else if (yDiatance > 50)
getParent().requestDisallowInterceptTouchEvent(false);
break;


case MotionEvent.ACTION_UP:
mDownX = 0;
mDownY = 0;


default:
break;
}
return super.onInterceptTouchEvent(ev);
}

// 主要布局,功能在Scrollview里面实现

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


    <LinearLayout
        android:id="@+id/first_ll"
        style="@style/NaviStyle"
        android:layout_alignParentTop="true" >


        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent" >


            <ImageView
                android:id="@+id/imgRefresh"
                android:layout_width="22dip"
                android:layout_height="25dip"
                android:layout_centerVertical="true"
                android:layout_marginLeft="15dip"
                android:src="@drawable/refresh" />


            <TextView
                android:id="@+id/txtShareTitle"
                style="@style/TitleTextStyle"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_centerInParent="true"
                android:text="@string/navi_title" />


            <LinearLayout
                android:id="@+id/imgPersonal"
                android:layout_width="wrap_content"
                android:layout_height="match_parent"
                android:layout_alignParentRight="true"
                android:gravity="center"
                android:orientation="vertical" >


                <ImageView
                    style="@style/ImgPersonStyle"
                    android:layout_marginLeft="10dip"
                    android:layout_marginRight="10dip" />
            </LinearLayout>
        </RelativeLayout>
    </LinearLayout>


    <com.shpj.hdsale.util.BulletinView
        android:id="@+id/roll_text"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_below="@+id/first_ll"
        android:background="@color/bg_color"
        android:padding="5dp"
        android:text="test"
        android:textSize="16sp" />


    <ScrollView
        android:id="@+id/poster_sc"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_below="@+id/roll_text"
        android:background="@color/bg_color"
        android:fillViewport="true"
        android:scrollbars="none" >


        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:orientation="vertical" >


            <com.zxing.view.MyViewPager
                android:id="@+id/pager"
                android:layout_width="match_parent"
                android:layout_height="match_parent" />
        </LinearLayout>
    </ScrollView>


    <LinearLayout
        android:id="@+id/dotGroup"
        android:layout_width="match_parent"
        android:layout_height="20dip"
        android:layout_alignParentBottom="true"
        android:layout_marginBottom="10dp"
        android:gravity="center_horizontal"
        android:orientation="horizontal" >
    </LinearLayout>


</RelativeLayout>

// ViewPager的子view布局

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical" android:layout_width="match_parent"
    android:layout_height="match_parent">
    <ImageView
        android:id="@+id/imgPoster"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:scaleType="fitCenter" />
</LinearLayout>


好的,主要的功能实现都写完了,由于公司项目原因,不能把整个项目代码贴出来,希望大家谅解,如果有什么不清楚的话,欢迎与我探讨。


转载请注明出处,谢谢

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值