Android 自定义 HorizontalScrollView 打造再多图片(控件)也不怕 OOM 的横向滑动效果,小白看完都学会了

android:scaleType=“centerCrop”

android:src=“@drawable/ic_launcher” />

<com.example.zhy_horizontalscrollview.MyHorizontalScrollView

android:id=“@+id/id_horizontalScrollView”

android:layout_width=“wrap_content”

android:layout_height=“150dp”

android:layout_gravity=“bottom”

android:background=“@android:color/white”

android:scrollbars=“none” >

<LinearLayout

android:id=“@+id/id_gallery”

android:layout_width=“wrap_content”

android:layout_height=“wrap_content”

android:layout_gravity=“center_vertical”

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 oldViewPos = 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.onCurrentImgChanged(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;

}
自我介绍一下,小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Android工程师,想要提升技能,往往是自己摸索成长或者是报班学习,但对于培训机构动则近万的学费,着实压力不小。自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年Android移动开发全套学习资料》,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。

img

img

img

img

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

《960全网最全Android开发笔记》

《379页Android开发面试宝典》

《507页Android开发相关源码解析》

因为文件太多,全部展示会影响篇幅,暂时就先列举这些部分截图

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。**

[外链图片转存中…(img-TIizcICk-1712359039519)]

[外链图片转存中…(img-82A6Bu1K-1712359039520)]

[外链图片转存中…(img-uMx9L3B3-1712359039520)]

[外链图片转存中…(img-Nv4xmb4e-1712359039520)]

[外链图片转存中…(img-nuoBX48Z-1712359039520)]

既有适合小白学习的零基础资料,也有适合3年以上经验的小伙伴深入学习提升的进阶课程,基本涵盖了95%以上Android开发知识点,真正体系化!

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频,并且会持续更新!

如果你觉得这些内容对你有帮助,可以扫码获取!!(备注:Android)

《960全网最全Android开发笔记》

[外链图片转存中…(img-Cr25587R-1712359039521)]

《379页Android开发面试宝典》

[外链图片转存中…(img-zBb3PkLF-1712359039521)]

《507页Android开发相关源码解析》

[外链图片转存中…(img-pyu4OtUu-1712359039521)]

因为文件太多,全部展示会影响篇幅,暂时就先列举这些部分截图

《互联网大厂面试真题解析、进阶开发核心学习笔记、全套讲解视频、实战项目源码讲义》点击传送门即可获取!

  • 30
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
对于动态加载数据并实现横向滑动效果HorizontalScrollView,你可以按照以下步骤进行操作: 1. 在你的布局文件中添加 HorizontalScrollView 控件: ```xml <HorizontalScrollView android:id="@+id/horizontalScrollView" android:layout_width="match_parent" android:layout_height="wrap_content"> <LinearLayout android:id="@+id/linearLayout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal"> <!-- 这里可以动态添加子视图 --> </LinearLayout> </HorizontalScrollView> ``` 2. 在你的代码中获取 HorizontalScrollView 和 LinearLayout 对象,并根据数据动态添加子视图: ```java HorizontalScrollView horizontalScrollView = findViewById(R.id.horizontalScrollView); LinearLayout linearLayout = findViewById(R.id.linearLayout); for (int i = 0; i < 数据集合.size(); i++) { final 数据类型 数据 = 数据集合.get(i); // 创建子视图 TextView textView = new TextView(this); textView.setText(数据.文本); textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 处理单项点击事件 // 这里可以根据需要执行相应的操作 } }); // 将子视图添加到 LinearLayout linearLayout.addView(textView); } ``` 3. 如果你希望每次只能选择一项,你可以在点击事件中记录当前选中的项,并在下次点击时取消上一次的选中效果: ```java private TextView lastSelectedView; // ... textView.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (lastSelectedView != null) { // 取消上一次选中的效果 lastSelectedView.setSelected(false); } // 设置当前选中的效果 textView.setSelected(true); lastSelectedView = textView; // 处理单项点击事件 // 这里可以根据需要执行相应的操作 } }); ``` 这样,你就可以实现在 HorizontalScrollView 中动态加载数据,并且只能单项点击的效果了。希望对你有帮助!

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值