安卓轮播图片的实现
程序员文章站
2022-07-14 12:53:57
...
一、原理
首先,将这些要轮播的图片和一些文本分别放置在不同的数据集合中,程序启动的时候默认显示一组图片和文本数据,然后启动一个定时器,每隔一段时间便替换掉显示的图片和文本数据,同时加入一些动画效果,已达到轮播的特效。同时,我们也要实现手指滑动图片达到轮播的效果。
二、实现
1、程序启动界面MainActivity
public class MainActivity extends AppCompatActivity implements ImageBannerFramLayout.FramLayoutLisenner{
private ImageBannerFramLayout mGroup;
private int[] ids = new int[] {
R.drawable.i1,//图片资源1
R.drawable.i2,//图片资源2
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//计算当前手机宽度
DisplayMetrics displayMetrics = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(displayMetrics);
int width = displayMetrics.widthPixels;
mGroup = (ImageBannerFramLayout) findViewById(R.id.image_group);
mGroup.setLisenner(this);
List<Bitmap> list = new ArrayList<>();
for (int i = 0; i < ids.length; i++) {
Bitmap bitmap = BitmapFactory.decodeResource(getResources(),ids[i]);
list.add(bitmap);
}
mGroup.addBitmaps(list);
}
@Override
public void chickImageIndex(int pos) {
Toast.makeText(this,"索引值 = " + pos,Toast.LENGTH_SHORT).show();
}
}
2、新建包view下面新建两个类
1)新建ImageBarnnerViewGroup类继承自ViewGroup
public class ImageBarnnerViewGroup extends ViewGroup {
private int children;//我们View Group的子视图总个数
private int childwidth;//子视图的宽度
private int childheight;//子视图的高度
private int x;//此时的x的值代表的是第一次按下的位置的横坐标,每一次移动过的过程中 移动之前的位置横坐标
private int index = 0;//代表名为每张图片的索引
private Scroller scroller;
/**
* 利用一个单击变量开关进行判断,离开屏幕的一瞬间判断用户的操作是点击
*/
private boolean isClick;//true的时候点击事件,false的时候不是点击事件
private ImageBarnnerLister lister;
private ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner;
public ImageBarnnerLister getLister() {
return lister;
}
public void setLister(ImageBarnnerLister lister) {
this.lister = lister;
}
public ImageBarnnerViewGroupLisnner getBarnnerViewGroupLisnner() {
return barnnerViewGroupLisnner;
}
public void setBarnnerViewGroupLisnner(ImageBarnnerViewGroupLisnner barnnerViewGroupLisnner) {
this.barnnerViewGroupLisnner = barnnerViewGroupLisnner;
}
public interface ImageBarnnerLister {
void chickImageIndex(int pos);//pos代表的是我们当前的图片的具体索引值
}
/**
* 实现轮播图底部圆点切换效果
* 自定义一个继承自FragmenLayou布局,利用FragmeLayout布局特性
*/
//自动轮播
private boolean isAuto = true;//默认情况下开启轮播
private Timer timer = new Timer();
private TimerTask timerTask;
@SuppressLint("HandlerLeak")
private android.os.Handler autohandler = new android.os.Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case 0://我们需要图片的自动轮播
if (++index >= children) {//如果是最后一张图片,从第一张开始
index = 0;
}
scrollTo(childwidth * index,0);
barnnerViewGroupLisnner.selectImage(index);
break;
default:
}
}
};
private void startAuto() {
isAuto = true;
}
private void stopAuto() {
isAuto = false;
}
/**
* 采用Timer,TimerTask,Handler三者结合的方式来实现自动轮播
*/
public ImageBarnnerViewGroup(Context context) {
super(context);
initObj();
}
public ImageBarnnerViewGroup(Context context, AttributeSet attrs) {
super(context, attrs);
initObj();
}
public ImageBarnnerViewGroup(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
initObj();
}
private void initObj() {
scroller = new Scroller(getContext());
timerTask = new TimerTask() {
@Override
public void run() {
if (isAuto) {//开启轮播图
autohandler.sendEmptyMessage(0);
}
}
};
timer.schedule(timerTask,100,3000);
}
@Override
public void computeScroll() {
super.computeScroll();
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(),0);
invalidate();//重绘
}
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//1.求出子视图的个数
children = getChildCount();//我们可以知道自试图的个数
if (0 == children)
{
setMeasuredDimension(0,0);
} else {
measureChildren(widthMeasureSpec, heightMeasureSpec);
//此时我们以第一个子视图=为基准,也就是说我们的View Group
View view = getChildAt(0);
childwidth = view.getMeasuredWidth();
childheight = view.getMeasuredHeight();
int width = view.getMeasuredWidth() * children;
setMeasuredDimension(width,childheight);
}
//2.测量子视图的宽度和高度
//3.根据子视图的狂赌和高度,求出该ViewGroup的宽度和高度
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return super.onInterceptTouchEvent(ev);
}
/**
* 用两种方式来实现轮播图的手动轮播
* 1,利用scrollTo,scrollBy 完成轮播图的手动轮播
* 1,利用Scroller 对象完成轮播图的手动效果
* @param event
* @return
*/
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN://表示用户按下的一瞬间
stopAuto();//停止图片轮播
if (!scroller.isFinished()) {
scroller.abortAnimation();
}
isClick = true;
x=(int)event.getX();
break;
case MotionEvent.ACTION_MOVE://表示用户按下之后在屏幕上移动的过程
int moveX = (int) event.getX();
int distance = moveX - x;
scrollBy(-distance,0);
x = moveX;
isClick = false;
break;
case MotionEvent.ACTION_UP://标识的是用户抬起的一瞬间
int scrollX = getScrollX();
index = (scrollX + childwidth / 2) / childwidth;
if (index < 0) { //已经滑动到了最左边
index = 0;
} else if (index > children - 1) {//说明已经滑动到了最右边
index = children - 1;
}
if (isClick) { //点击事件
lister.chickImageIndex(index);
} else {
int dx = index * childwidth - scrollX;
scroller.startScroll(scrollX,0,dx,0);
postInvalidate();
barnnerViewGroupLisnner.selectImage(index);
}
startAuto();//开启图片轮播
break;
default:
}
return true;
//返回true的目的是告诉该View Group容器的父View 我们已经处理好了该事件
}
@Override
protected void onLayout(boolean b, int i, int i1, int i2, int i3) {
if (b) {
int lefrMargin = 0;
for (int j = 0; j < children; j++) {
View view = getChildAt(j);
view.layout(lefrMargin,0,lefrMargin + childwidth,childheight);
lefrMargin += childwidth;
}
}
}
public interface ImageBarnnerViewGroupLisnner{
void selectImage(int index);
}
}
2)新建ImageBannerFramLayout类继承自FrameLayout实现两个接口
public class ImageBannerFramLayout extends FrameLayout implements ImageBarnnerViewGroup.ImageBarnnerViewGroupLisnner,ImageBarnnerViewGroup.ImageBarnnerLister{
private ImageBarnnerViewGroup imageBarnnerViewGroup;
private LinearLayout linearLayout;
private FramLayoutLisenner lisenner;
public FramLayoutLisenner getLisenner() {
return lisenner;
}
public void setLisenner(FramLayoutLisenner lisenner) {
this.lisenner = lisenner;
}
public ImageBannerFramLayout(@NonNull Context context) {
super(context);
initImageBarnnerViewGroup();
initDotLinearlayout();
}
public ImageBannerFramLayout(@NonNull Context context, @Nullable AttributeSet attrs) {
super(context, attrs);
initImageBarnnerViewGroup();
initDotLinearlayout();
}
public ImageBannerFramLayout(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initImageBarnnerViewGroup();
initDotLinearlayout();
}
public void addBitmaps(List<Bitmap> list) {
for (int i = 0; i < list.size(); i++) {
Bitmap bitmap = list.get(i);
addBitmapToImageBarnnerViewGroup(bitmap);
addDotToLinearlayout();
}
}
private void addDotToLinearlayout() {
ImageView iv = new ImageView(getContext());
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams
(LinearLayout.LayoutParams.WRAP_CONTENT,LinearLayout.LayoutParams.MATCH_PARENT);
layoutParams.setMargins(5,5,5,5);
iv.setLayoutParams(layoutParams);
iv.setImageResource(R.drawable.dot_normal);
linearLayout.addView(iv);
}
private void addBitmapToImageBarnnerViewGroup(Bitmap bitmap) {
ImageView imageView = new ImageView(getContext());
imageView.setScaleType(ImageView.ScaleType.CENTER_CROP);
imageView.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,ViewGroup.LayoutParams.WRAP_CONTENT));
imageView.setImageBitmap(bitmap);
imageBarnnerViewGroup.addView(imageView);
}
//初始化自定义图片轮播功能核心类
private void initImageBarnnerViewGroup() {
imageBarnnerViewGroup = new ImageBarnnerViewGroup(getContext());
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams
(FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.MATCH_PARENT);
imageBarnnerViewGroup.setLayoutParams(layoutParams);
imageBarnnerViewGroup.setBarnnerViewGroupLisnner(this);//将linsnner传递给Framlayout
imageBarnnerViewGroup.setLister(this);
addView(imageBarnnerViewGroup);
}
//初始化底部圆点布局
private void initDotLinearlayout() {
linearLayout = new LinearLayout(getContext());
FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams
(FrameLayout.LayoutParams.MATCH_PARENT, 40);
linearLayout.setLayoutParams(layoutParams);
linearLayout.setOrientation(LinearLayout.HORIZONTAL);
linearLayout.setGravity(Gravity.CENTER);
linearLayout.setBackgroundColor(Color.RED);
addView(linearLayout);
FrameLayout.LayoutParams layoutParams1 = (LayoutParams) linearLayout.getLayoutParams();
layoutParams.gravity = Gravity.BOTTOM;
linearLayout.setLayoutParams(layoutParams1);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
linearLayout.setAlpha(0.5f);
} else {
linearLayout.getBackground().setAlpha(100);
}
}
@Override
public void selectImage(int index) {
int count = linearLayout.getChildCount();
for (int i = 0;i < count; i++) {
ImageView iv = (ImageView) linearLayout.getChildAt(i);
if (i == index) {
iv.setImageResource(R.drawable.dot_select);
} else {
iv.setImageResource(R.drawable.dot_normal);
}
}
}
@Override
public void chickImageIndex(int pos) {
lisenner.chickImageIndex(pos);
}
public interface FramLayoutLisenner{
void chickImageIndex(int pos);
}
}
3、程序布局页面activity_main
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.example.tony.imagegroup.view.ImageBannerFramLayout
android:id="@+id/image_group"
android:layout_width="match_parent"
android:layout_height="200dp">
</com.example.tony.imagegroup.view.ImageBannerFramLayout>
</RelativeLayout>
4、新建两个drawable资源文件dot_normal.xml和dot_select.xml,实现轮播图底部小圆点
不同的是前者颜色为白色后者为黑色
<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="oval">
<solid android:color="@android:color/white"/>
<size android:height="10dp"
android:width="10dp"/>
</shape>
三、运行结果
上一篇: 安卓 实现滑动效果