Android 自定义 HorizontalScrollView 打造再多图片(控件)也不怕 OOM 的横向滑动效果

android:orientation=“horizontal” >

</com.example.zhy_horizontalscrollview.MyHorizontalScrollView>

没任何变化,除了把类名改成了我们自定义的类~

2、为了和国际接轨,我们也搞个Adapter,类似BaseAdapter

package com.example.zhy_horizontalscrollview;

import java.util.List;

import android.content.Context;

import android.view.LayoutInflater;

import android.view.View;

import android.view.ViewGroup;

import android.widget.BaseAdapter;

import android.widget.ImageView;

import android.widget.TextView;

public class HorizontalScrollViewAdapter

{

private Context mContext;

private LayoutInflater mInflater;

private List mDatas;

public HorizontalScrollViewAdapter(Context context, List mDatas)

{

this.mContext = context;

mInflater = LayoutInflater.from(context);

this.mDatas = mDatas;

}

public int getCount()

{

return mDatas.size();

}

public Object getItem(int position)

{

return mDatas.get(position);

}

public long getItemId(int position)

{

return position;

}

public View getView(int position, View convertView, ViewGroup parent)

{

ViewHolder viewHolder = null;

if (convertView == null)

{

viewHolder = new ViewHolder();

convertView = mInflater.inflate(

R.layout.activity_index_gallery_item, parent, false);

viewHolder.mImg = (ImageView) convertView

.findViewById(R.id.id_index_gallery_item_image);

viewHolder.mText = (TextView) convertView

.findViewById(R.id.id_index_gallery_item_text);

convertView.setTag(viewHolder);

} else

{

viewHolder = (ViewHolder) convertView.getTag();

}

viewHolder.mImg.setImageResource(mDatas.get(position));

viewHolder.mText.setText("some info ");

return convertView;

}

private class ViewHolder

{

ImageView mImg;

TextView mText;

}

}

3、下面先看用法:

package com.example.zhy_horizontalscrollview;

import java.util.ArrayList;

import java.util.Arrays;

import java.util.List;

import android.app.Activity;

import android.graphics.Color;

import android.os.Bundle;

import android.view.View;

import android.view.Window;

import android.widget.ImageView;

import com.example.zhy_horizontalscrollview.MyHorizontalScrollView.CurrentImageChangeListener;

import com.example.zhy_horizontalscrollview.MyHorizontalScrollView.OnItemClickListener;

public class MainActivity extends Activity

{

private MyHorizontalScrollView mHorizontalScrollView;

private HorizontalScrollViewAdapter mAdapter;

private ImageView mImg;

private List mDatas = new ArrayList(Arrays.asList(

R.drawable.a, R.drawable.b, R.drawable.c, R.drawable.d,

R.drawable.e, R.drawable.f, R.drawable.g, R.drawable.h,

R.drawable.l));

@Override

protected void onCreate(Bundle savedInstanceState)

{

super.onCreate(savedInstanceState);

requestWindowFeature(Window.FEATURE_NO_TITLE);

setContentView(R.layout.activity_main);

mImg = (ImageView) findViewById(R.id.id_content);

mHorizontalScrollView = (MyHorizontalScrollView) findViewById(R.id.id_horizontalScrollView);

mAdapter = new HorizontalScrollViewAdapter(this, mDatas);

//添加滚动回调

mHorizontalScrollView

.setCurrentImageChangeListener(new CurrentImageChangeListener()

{

@Override

public void onCurrentImgChanged(int position,

View viewIndicator)

{

mImg.setImageResource(mDatas.get(position));

viewIndicator.setBackgroundColor(Color

.parseColor(“#AA024DA4”));

}

});

//添加点击回调

mHorizontalScrollView.setOnItemClickListener(new OnItemClickListener()

{

@Override

public void onClick(View view, int position)

{

mImg.setImageResource(mDatas.get(position));

view.setBackgroundColor(Color.parseColor(“#AA024DA4”));

}

});

//设置适配器

mHorizontalScrollView.initDatas(mAdapter);

}

}

用起来是不是有点像ListView,初始化数据适配器,然后设置数据适配器,然后就是设置各种回调~~

如果仅仅是一堆图片展示,类似商品切换,更见简单,就不需要设置滚动监听和点击监听了~

4、最后看自定义的MyHorizontalScrollView类

package com.example.zhy_horizontalscrollview;

import java.util.HashMap;

import java.util.Map;

import android.content.Context;

import android.graphics.Color;

import android.util.AttributeSet;

import android.util.DisplayMetrics;

import android.util.Log;

import android.view.MotionEvent;

import android.view.View;

import android.view.View.OnClickListener;

import android.view.WindowManager;

import android.widget.HorizontalScrollView;

import android.widget.LinearLayout;

public class MyHorizontalScrollView extends HorizontalScrollView implements

OnClickListener

{

/**

  • 图片滚动时的回调接口

  • @author zhy

*/

public interface CurrentImageChangeListener

{

void onCurrentImgChanged(int position, View viewIndicator);

}

/**

  • 条目点击时的回调

  • @author zhy

*/

public interface OnItemClickListener

{

void onClick(View view, int pos);

}

private CurrentImageChangeListener mListener;

private OnItemClickListener mOnClickListener;

private static final String TAG = “MyHorizontalScrollView”;

/**

  • HorizontalListView中的LinearLayout

*/

private LinearLayout mContainer;

/**

  • 子元素的宽度

*/

private int mChildWidth;

/**

  • 子元素的高度

*/

private int mChildHeight;

/**

  • 当前最后一张图片的index

*/

private int mCurrentIndex;

/**

  • 当前第一张图片的下标

*/

private int mFristIndex;

/**

  • 当前第一个View

*/

private View mFirstView;

/**

  • 数据适配器

*/

private HorizontalScrollViewAdapter mAdapter;

/**

  • 每屏幕最多显示的个数

*/

private int mCountOneScreen;

/**

  • 屏幕的宽度

*/

private int mScreenWitdh;

/**

  • 保存View与位置的键值对

*/

private Map<View, Integer> mViewPos = new HashMap<View, Integer>();

public MyHorizontalScrollView(Context context, AttributeSet attrs)

{

super(context, attrs);

// 获得屏幕宽度

WindowManager wm = (WindowManager) context

.getSystemService(Context.WINDOW_SERVICE);

DisplayMetrics outMetrics = new DisplayMetrics();

wm.getDefaultDisplay().getMetrics(outMetrics);

mScreenWitdh = outMetrics.widthPixels;

}

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec)

{

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

mContainer = (LinearLayout) getChildAt(0);

}

/**

  • 加载下一张图片

*/

protected void loadNextImg()

{

// 数组边界值计算

if (mCurrentIndex == mAdapter.getCount() - 1)

{

return;

}

//移除第一张图片,且将水平滚动位置置0

scrollTo(0, 0);

mViewPos.remove(mContainer.getChildAt(0));

mContainer.removeViewAt(0);

//获取下一张图片,并且设置onclick事件,且加入容器中

View view = mAdapter.getView(++mCurrentIndex, null, mContainer);

view.setOnClickListener(this);

mContainer.addView(view);

mViewPos.put(view, mCurrentIndex);

//当前第一张图片小标

mFristIndex++;

//如果设置了滚动监听则触发

if (mListener != null)

{

notifyCurrentImgChanged();

}

}

/**

  • 加载前一张图片

*/

protected void loadPreImg()

{

//如果当前已经是第一张,则返回

if (mFristIndex == 0)

return;

//获得当前应该显示为第一张图片的下标

int index = mCurrentIndex - mCountOneScreen;

if (index >= 0)

{

// mContainer = (LinearLayout) getChildAt(0);

//移除最后一张

int oldVie外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传

资料获取→专栏
wPos = mContainer.getChildCount() - 1;

mViewPos.remove(mContainer.getChildAt(oldViewPos));

mContainer.removeViewAt(oldViewPos);

//将此View放入第一个位置

View view = mAdapter.getView(index, null, mContainer);

mViewPos.put(view, index);

mContainer.addView(view, 0);

view.setOnClickListener(this);

//水平滚动位置向左移动view的宽度个像素

scrollTo(mChildWidth, 0);

//当前位置–,当前第一个显示的下标–

mCurrentIndex–;

mFristIndex–;

//回调

if (mListener != null)

{

notifyCurrentImgChanged();

}

}

}

/**

  • 滑动时的回调

*/

public void notifyCurrentImgChanged()

{

//先清除所有的背景色,点击时会设置为蓝色

for (int i = 0; i < mContainer.getChildCount(); i++)

{

mContainer.getChildAt(i).setBackgroundColor(Color.WHITE);

}

mListener.on
CurrentImgChanged(mFristIndex, mContainer.getChildAt(0));

}

/**

  • 初始化数据,设置数据适配器

  • @param mAdapter

*/

public void initDatas(HorizontalScrollViewAdapter mAdapter)

{

this.mAdapter = mAdapter;

mContainer = (LinearLayout) getChildAt(0);

// 获得适配器中第一个View

final View view = mAdapter.getView(0, null, mContainer);

mContainer.addView(view);

// 强制计算当前View的宽和高

if (mChildWidth == 0 && mChildHeight == 0)

{

int w = View.MeasureSpec.makeMeasureSpec(0,

View.MeasureSpec.UNSPECIFIED);

int h = View.MeasureSpec.makeMeasureSpec(0,

View.MeasureSpec.UNSPECIFIED);

view.measure(w, h);

mChildHeight = view.getMeasuredHeight();

mChildWidth = view.getMeasuredWidth();

Log.e(TAG, view.getMeasuredWidth() + “,” + view.getMeasuredHeight());

mChildHeight = view.getMeasuredHeight();

// 计算每次加载多少个View

mCountOneScreen = mScreenWitdh / mChildWidth+2;

Log.e(TAG, "mCountOneScreen = " + mCountOneScreen

  • " ,mChildWidth = " + mChildWidth);

}

//初始化第一屏幕的元素

initFirstScreenChildren(mCountOneScreen);

}

/**

  • 加载第一屏的View

  • @param mCountOneScreen

*/

public void initFirstScreenChildren(int mCountOneScreen)

{

mContainer = (LinearLayout) getChildAt(0);

mContainer.removeAllViews();

mViewPos.clear();

for (int i = 0; i < mCountOneScreen; i++)

{

View view = mAdapter.getView(i, null, mContainer);

view.setOnClickListener(this);

mContainer.addView(view);

mViewPos.put(view, i);

mCurrentIndex = i;

}

if (mListener != null)

{

notifyCurrentImgChanged();

}

}

@Override

public boolean onTouchEvent(MotionEvent ev)

{

switch (ev.getAction())

{

case MotionEvent.ACTION_MOVE:

// Log.e(TAG, getScrollX() + “”);

int scrollX = getScrollX();

// 如果当前scrollX为view的宽度,加载下一张,移除第一张

if (scrollX >= mChildWidth)

{

loadNextImg();

}

// 如果当前scrollX = 0, 往前设置一张,移除最后一张

if (scrollX == 0)

{

loadPreImg();

}

break;

}

return super.onTouchEvent(ev);

}

@Override

public void onClick(View v)

{

if (mOnClickListener != null)

{

for (int i = 0; i < mContainer.getChildCount(); i++)

{

mContainer.getChildAt(i).setBackgroundColor(Color.WHITE);

}

mOnClickListener.onClick(v, mViewPos.get(v));

}

}

public void setOnItemClickListener(OnItemClickListener mOnClickListener)

{

this.mOnClickListener = mOnClickListener;

}

public void setCurrentImageChangeListener(

CurrentImageChangeListener mListener)

{

this.mListener = mListener;

}

}

首先,加载第一个Item,根据item的宽计算当前屏幕可以加载多少张图片,然后初始化第一屏的图片,接下来就是从写onTouchEvent,在其中监听用户的ACTION_MOVE,然后根据移动的距离加载前一张或者后一张,同时动态移除不可见的View,回收内存~~~~

代码中有个Map专门存储View和posion的,主要是为了给点击回调提供当前的View的位置,有点类似:Android 自定义 ViewPager 打造千变万化的图片切换效果里面的Map的巧妙用法~~

是不是完全实现了ViewPager和HorizontalScrollView的合体~~~HorizontalScrollView的效果,ViewPager的特性~~~~

最后贴一下旋转屏幕后的效果图:

可以看出,不仅是做相册,还是图片轮播想过都是刚刚的!

如果你的项目中需要用到Gallery类似的效果,果断使用上例尝试吧~~

各位看官没事点个赞,留个言呗~

BackgroundColor(Color.WHITE);

}

mOnClickListener.onClick(v, mViewPos.get(v));

}

}

public void setOnItemClickListener(OnItemClickListener mOnClickListener)

{

this.mOnClickListener = mOnClickListener;

}

public void setCurrentImageChangeListener(

CurrentImageChangeListener mListener)

{

this.mListener = mListener;

}

}

首先,加载第一个Item,根据item的宽计算当前屏幕可以加载多少张图片,然后初始化第一屏的图片,接下来就是从写onTouchEvent,在其中监听用户的ACTION_MOVE,然后根据移动的距离加载前一张或者后一张,同时动态移除不可见的View,回收内存~~~~

代码中有个Map专门存储View和posion的,主要是为了给点击回调提供当前的View的位置,有点类似:Android 自定义 ViewPager 打造千变万化的图片切换效果里面的Map的巧妙用法~~

是不是完全实现了ViewPager和HorizontalScrollView的合体~~~HorizontalScrollView的效果,ViewPager的特性~~~~

最后贴一下旋转屏幕后的效果图:

可以看出,不仅是做相册,还是图片轮播想过都是刚刚的!

如果你的项目中需要用到Gallery类似的效果,果断使用上例尝试吧~~

各位看官没事点个赞,留个言呗~

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值