本文是在 http://blog.youkuaiyun.com/lmj623565791/article/details/38140505 的基础上加工的,鸿洋_写的思路非常完美,夸张点就是无人出其右。
当然也存在问题,首先就是如果一屏不够,奔溃(小问题);还有很重要的问题,就是体验差,本人在他基础上改了,如果存在问题,非常欢迎大家指导,相互学习、相互交流。
大概思路:
1.定义一个adapter适配器,用于每次新增item;
2.自定义HorizontalScrollView,初始化init时,计算item宽度等,第一次展示多少item显示;
3.滑动加载,按照删除多少就新增多少的原则。
直接上代码,里面已经注释说明了,不过多做解释
1.自定义一个adapter(注意不要集成baseadapter)
HorizontalScrollViewAdapter.java
import android.content.Context; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import com.bumptech.glide.Glide; import com.master.R; import com.master.basecommon.baseutils.ViewSetVoluationUtils; import com.master.core.base.ListViewHolder; import java.io.File; import java.util.HashMap; import java.util.List; /** * 项 目 名: * 修 改 人: gq * <p> * 修改时间: 2017/6/29 * <p> * <横向相册一览自定义adapter> */ public class HorizontalScrollViewAdapter { private Context mContext; private List<HashMap<String, String>> mlist; public HorizontalScrollViewAdapter(Context context, List<HashMap<String, String>> mlist) { this.mContext = context; this.mlist = mlist; } public int getCount() { return mlist.size(); } public Object getItem(int position) { return mlist.get(position); } public long getItemId(int position) { return position; } /** * 更新 * * @param parent * @param position */ public void notifyChangeData(ViewGroup parent, int position, boolean isSelected) { ViewHolder viewHolder = (ViewHolder)parent.getChildAt(position).getTag(); if (!isSelected) { viewHolder.imgSelected.setVisibility(View.GONE); } else { viewHolder.imgSelected.setVisibility(View.VISIBLE); } } public View getView(final int position, View convertView, ViewGroup parent) { ViewHolder viewHolder; if (convertView == null) { viewHolder = new ViewHolder(); LayoutInflater inflator = (LayoutInflater)parent.getContext() .getSystemService(Context.LAYOUT_INFLATER_SERVICE); convertView = inflator.inflate(R.layout.adapter_gridview_item, null); viewHolder.imgPhoto = ListViewHolder.get(convertView, R.id.img_photo); viewHolder.imgFlag = ListViewHolder.get(convertView, R.id.img_flag); viewHolder.imgSelected = ListViewHolder.get(convertView, R.id.img_selected); convertView.setTag(viewHolder); } else { viewHolder = (ViewHolder)convertView.getTag(); } if (mlist.get(position).get("mime_type").equals("video/mp4")) { ViewSetVoluationUtils.setViewVisibility(viewHolder.imgFlag, View.VISIBLE); Glide.with(mContext).load(R.mipmap.release_photo_video).into(viewHolder.imgFlag); } else { if (mlist.get(position).get("mime_type").equals("image/gif")) { ViewSetVoluationUtils.setViewVisibility(viewHolder.imgFlag, View.VISIBLE); Glide.with(mContext).load(R.mipmap.release_photo_gif).into(viewHolder.imgFlag); } else { ViewSetVoluationUtils.setViewVisibility(viewHolder.imgFlag, View.GONE); } } Glide.with(mContext) .load(new File(mlist.get(position).get("_data"))) .asBitmap() .override(90, 90) .placeholder(R.mipmap.scan_qrcode_slt_pic) .centerCrop() .into(viewHolder.imgPhoto); return convertView; } private static class ViewHolder { ImageView imgPhoto;// 图片 ImageView imgFlag;// 图片标签,是gif,普通,还是视频 ImageView imgSelected;// 图片被选中标识 } }
xml布局文件:
2.自定义 HorizontalScrollView 文件<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="@color/transparent" android:orientation="vertical"> <ImageView android:id="@+id/img_photo" android:layout_width="@dimen/dp_90" android:scaleType="centerCrop" android:src="@mipmap/scan_qrcode_slt_pic" android:layout_height="@dimen/dp_90" /> <ImageView android:id="@+id/img_flag" android:visibility="gone" android:layout_width="@dimen/dp_30" android:layout_height="@dimen/dp_15" android:background="@color/transparent" android:scaleType="fitEnd" android:src="@mipmap/release_photo_video" android:layout_marginTop="@dimen/dp_5" android:layout_marginRight="@dimen/dp_5" android:layout_alignRight="@+id/img_photo"/> <ImageView android:id="@+id/img_selected" android:layout_width="wrap_content" android:visibility="gone" android:src="@mipmap/release_photo_selected" android:layout_alignRight="@+id/img_photo" android:layout_alignBottom="@+id/img_photo" android:layout_marginBottom="@dimen/dp_5" android:layout_marginRight="@dimen/dp_5" android:layout_height="wrap_content" /> </RelativeLayout>
import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.View; import android.widget.HorizontalScrollView; import android.widget.LinearLayout; import com.master.core.view.adapter.HorizontalScrollViewAdapter; import com.master.utils.DisplayUtils; import java.util.HashMap; import java.util.Map; /** * 项 目 名: * 修 改 人: gq<br/> * 修改时间: 2017/6/29<br/> * <自定义HorizontalScrollview> */ public class MySpeicailHorizontalScrollView extends HorizontalScrollView implements View.OnClickListener { /** * 屏幕的宽度 */ private int mScreenWitdh; /** * 数据适配器 */ private HorizontalScrollViewAdapter mAdapter; /** * HorizontalListView中的LinearLayout */ private LinearLayout mContainer; private int imgSelected = -1; /** * 条目点击时的回调 * * @author zhy * */ public interface OnItemClickListener { void onClick(View view, int position); } private OnItemClickListener mOnClickListener; public void setOnItemClickListener(OnItemClickListener mOnClickListener) { this.mOnClickListener = mOnClickListener; } /** * 保存View与位置的键值对 */ private Map<View, Integer> mViewPos = new HashMap<View, Integer>(); /** * 子元素的宽度 */ private int mChildWidth; /** * 子元素的高度 */ private int mChildHeight; /** * 每屏幕最多显示的个数,个人建议一屏显示最好不要少于30 */ private final int mCountOneScreen = 30; /** * 当前最后一张图片的index */ private int mCurrentIndex; /** * 当前第一张图片的下标 */ private int mFristIndex; // 手指按下的X坐标 private float downX; private Context context; private final String TAG = "MyHorizontalScrollView"; public MySpeicailHorizontalScrollView(Context context, AttributeSet attrs) { super(context, attrs); this.context = context; mScreenWitdh = DisplayUtils.getScreenWidth(context); } /** * 初始化数据,设置数据适配器 * * @param mAdapter */ public void initDatas(HorizontalScrollViewAdapter mAdapter) { this.mAdapter = mAdapter; mContainer = (LinearLayout)this.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()); } // 初始化第一屏幕的元素,个数不能超过图片总个数 initFirstScreenChildren(mCountOneScreen > mAdapter.getCount() ? mAdapter.getCount() : mCountOneScreen); } /** * 加载第一屏的View * * @param mCountOneScreen */ public void initFirstScreenChildren(int mCountOneScreen) { mContainer.removeAllViews(); mViewPos.clear(); for (int i = 0; i < mCountOneScreen; i++) { addItem(i, true); mCurrentIndex = i; } } @Override public void onClick(View v) { imgSelected = mViewPos.get(v); mAdapter.notifyChangeData(mContainer, imgSelected - mFristIndex, true); if (mOnClickListener != null) { mOnClickListener.onClick(v, mViewPos.get(v)); } } @Override public boolean dispatchTouchEvent(MotionEvent ev) { // 如果一屏就显示完,则不需要滑动加载更多 if (mCountOneScreen < mAdapter.getCount()) { if (ev.getAction() == MotionEvent.ACTION_DOWN) { downX = ev.getX(); } else if (ev.getAction() == MotionEvent.ACTION_UP) { float upX = ev.getX(); int scrollX = getScrollX(); // 如果当前scrollX达到临界值加载更多右边图片 if (upX < downX) { int moveLeftAreaNums = scrollX / mChildWidth; loadNextImg(moveLeftAreaNums); } // upX = downX表示点击事件 else if (upX > downX) { // 滑动状态下,可删除item个数 int moveRightAreaNums = (mViewPos.size() * mChildWidth - (scrollX + mScreenWitdh)) / mChildWidth; // 删除多少张,添加多少张 loadPreImg(moveRightAreaNums); } // 防止滑动过程中删除了该view,再次滑动新增该view,选中状态被清洗 if (imgSelected != -1 && (imgSelected >= mFristIndex && imgSelected <= mCurrentIndex)) { // 滑动 if (upX != downX) { mAdapter.notifyChangeData(mContainer, imgSelected - mFristIndex, true); } // 点击 else { // 点击先处理前一个状态,再在onclick方法中处理刚被点击的状态 mAdapter.notifyChangeData(mContainer, imgSelected - mFristIndex, false); } } } } return super.dispatchTouchEvent(ev); } @Override public void fling(int velocityX) { super.fling(velocityX / 3); } /** * 加载下一张图片 * */ protected void loadNextImg(int loadNextNums) { // 数组边界值计算 if ((mCurrentIndex == mAdapter.getCount() - 1) || loadNextNums == 0) { return; } scrollBy(-mChildWidth, 0); removeItem(0); // 当前第一张图片小标 mFristIndex++; // 获取下一张图片 addItem(++mCurrentIndex, true); loadNextImg(--loadNextNums); } /** * 加载前一张图片 */ protected void loadPreImg(int loadPreNums) { // 如果当前已经是第一张,则返回 if (mFristIndex == 0 || loadPreNums == 0) { return; } // 移除最后一张 int oldViewPos = mContainer.getChildCount() - 1; removeItem(oldViewPos); // 最后一个的位置改变 mCurrentIndex--; // 将此View放入第一个位置 addItem(--mFristIndex, false); // 水平滚动位置向左移动view的宽度个像素 scrollBy(mChildWidth, 0); loadPreImg(--loadPreNums); } /** * 删除item * * @param index */ private void removeItem(int index) { mViewPos.remove(mContainer.getChildAt(index)); mContainer.removeViewAt(index); } /** * 新增item,并且设置onclick事件,且加入容器中 * * @param flag true表示后面添加item,false表示最前面添加item */ private void addItem(int index, boolean flag) { View view = mAdapter.getView(index, null, mContainer); view.setOnClickListener(this); if (flag) { mContainer.addView(view); } else { mContainer.addView(view, 0); } mViewPos.put(view, index); } }
3.activity中的引用:
//list集合里面存放全部图片集合
mAdapter = new HorizontalScrollViewAdapter(this, list); // 添加点击回调 hzScrollView.setOnItemClickListener(new MySpeicailHorizontalScrollView.OnItemClickListener() { @Override public void onClick(View view, int position) { //editPosition = position; } }); // 设置适配器 hzScrollView.initDatas(mAdapter);
根据以上搞定了,可以先根据以上做一个demo看看,然后在根据自己的需求进行修改
本人Q:1105107264,加好友注意备注