在公司是经常用到安卓的,所以我一有空就会自学,并把学到的记下来。下面介绍的是我自己练手的一个模仿某商城的小项目,用到的都是安卓很基础的知识点,今天要说的是轮播图涉及到的知识点-ViewPager(也可以用Banner实现),同时会涉及到一些其他的基础知识。先看看界面:
ViewPager简介:
视图翻页工具,可以切换多个页面。我们使用的是最新的androidx包下的。用法就是通过创建适配器adapter给它填充多个View(常见的ImageView),这样就可以左右翻动切换为不同的视图。
(1)activity_main.xml中加入:
把轮播图(id为vp_main_banner的ViewPager)和它下方的一排小圆点(id为ll_main_points_container的LinearLayout)一起放在一个RelativeLayout(相对布局)中
(2)ViewPager需要一个适配器,自定义一个BannerPagerAdapter.java:
package com.alibaba.taobao.controller.adapter;
import android.graphics.Color;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.viewpager.widget.PagerAdapter;
import com.alibaba.taobao.model.bean.ArcImageView;
import java.util.List;
public class BannerPagerAdapter extends PagerAdapter {
private List bannerImgs = null;
@Override
public Object instantiateItem(ViewGroup container, int position) {
ArcImageView imageView = new ArcImageView(container.getContext());
imageView.setImageResource(bannerImgs.get(position % bannerImgs.size()));
imageView.setScaleType(ImageView.ScaleType.FIT_XY);
container.addView(imageView);
return imageView;
}
@Override
public void destroyItem(ViewGroup container, int position, Object object) {
container.removeView((View) object);
}
@Override
public int getCount() {
if (bannerImgs != null) {
return Integer.MAX_VALUE;
}
return 0;
}
@Override
public boolean isViewFromObject(View view, Object object) {
return view == object;
}
public void setData(List bannerImgs) {
this.bannerImgs = bannerImgs;
}
public int getDataRealSize() {
if (null != bannerImgs) {
return bannerImgs.size();
}
return 0;
}
}
注意这个PagerAdapter是直接用androidx包下面的,如果你还停留在support包,可以在项目根目录下将gradle.properties中
将以上两项都改为false就好啦.
我们自定义的BannerPagerAdapter重写了instantiateItem()、destroyItem()、getCount()、isViewFromObject()这四个方法,并添加了setData()和getDataRealSize()方法。类中的bannerImgs是数据源,会在setData()方法中被初始化。重写的第一个方法作用就是创建ImageView (ArcImageView是我们自己写的ImageView),并把它设置到容器中。第二个方法是为了回收不必要的资源。第三个方法是返回ViewPager总共有几页,就像一本书有多少页可以翻,我们为了实现自动无限轮播,就把这个返回值设为Int最大值:Integer.MAX_VALUE。
(3)我们本来是在适配器往ViewPager加入广告图(ImageView类型,只能为矩形),但是我想把那块区域做成下边拱起一个弧形,所以ImageView需要重写onDraw()方法,自己写一个ArcImageView.java:
package com.alibaba.taobao.model.bean;
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Path;
import android.util.AttributeSet;
import android.widget.ImageView;
import androidx.annotation.Nullable;
import androidx.appcompat.widget.AppCompatImageView;
import com.alibaba.taobao.R;
/**
* Android 实现弧形View
*
*/
public class ArcImageView extends AppCompatImageView {
/*
*弧形高度
*/
private int mArcHeight;
private static final String TAG = "ArcImageView";
public ArcImageView(Context context) {
this(context, null);
}
public ArcImageView(Context context, @Nullable AttributeSet attrs) {
this(context, attrs, 0);
}
public ArcImageView(Context context, @Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.ArcImageView);
mArcHeight = typedArray.getDimensionPixelSize(R.styleable.ArcImageView_arcHeight, 20);
}
@Override
protected void onDraw(Canvas canvas) {
Path path = new Path();
path.moveTo(0, 0);
path.lineTo(0, getHeight());
path.quadTo(getWidth() / 2, getHeight() - 2 * mArcHeight, getWidth(), getHeight());//贝塞尔曲线
path.lineTo(getWidth(), 0);
path.close();
canvas.clipPath(path);
super.onDraw(canvas);
}
}
(4)在项目资源目录res下values目录下新建一个attrs.xml:
(5)最后是MainActivity.java ,不要忘了实现翻页监听接口ViewPager.OnPageChangeListener:
package com.alibaba.taobao;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager.widget.ViewPager;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.Window;
import android.view.WindowManager;
import android.widget.EditText;
import android.widget.LinearLayout;
import com.alibaba.taobao.controller.adapter.BannerPagerAdapter;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity implements ViewPager.OnPageChangeListener {
private ViewPager vp_main_banner;
private BannerPagerAdapter bannerPagerAdapter;
private static List bannerImgs;
private LinearLayout ll_main_points_container;
private final int POINT_NORMAL_ALPHA = 120;
//准备数据源
static {
bannerImgs = new ArrayList<>();
bannerImgs.add(R.drawable.banner01);
bannerImgs.add(R.drawable.banner02);
bannerImgs.add(R.drawable.banner03);
bannerImgs.add(R.drawable.banner04);
}
private Handler handler;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
supportRequestWindowFeature(Window.FEATURE_NO_TITLE);
//透明状态栏
getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS);
//透明导航栏
//getWindow().addFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_NAVIGATION);
setContentView(R.layout.activity_main);
initView();
//用handler自动轮播
handler = new Handler();
}
@Override
public void onAttachedToWindow() {
super.onAttachedToWindow();
handler.post(autoPlayTask);
}
@Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
handler.removeCallbacks(autoPlayTask);
}
@Override
public void onPointerCaptureChanged(boolean hasCapture) {
}
private Runnable autoPlayTask = new Runnable() {
@Override
public void run() {
//实现自动轮播,每两秒切换ViewPager里的图片到下一个
int item = vp_main_banner.getCurrentItem();
vp_main_banner.setCurrentItem(++item, false);
handler.postDelayed(this, 2000);
}
};
private void initView() {
vp_main_banner = findViewById(R.id.vp_main_banner);
bannerPagerAdapter = new BannerPagerAdapter();
vp_main_banner.setAdapter(bannerPagerAdapter);
vp_main_banner.addOnPageChangeListener(this);
bannerPagerAdapter.setData(bannerImgs);
bannerPagerAdapter.notifyDataSetChanged();
ll_main_points_container = findViewById(R.id.ll_main_points_container);
initPoints();
vp_main_banner.setCurrentItem(bannerPagerAdapter.getDataRealSize() * 100, false);
}
//初始化下方的一排小圆点,全为白色半透明
private void initPoints() {
for (int i = 0; i < bannerImgs.size(); i++) {
View point = new View(this);
LinearLayout.LayoutParams layoutParams = new LinearLayout.LayoutParams(20, 20);
layoutParams.leftMargin = 10;
point.setBackgroundResource(R.drawable.point_normal_shape);
point.getBackground().setAlpha(POINT_NORMAL_ALPHA);
point.setLayoutParams(layoutParams);
ll_main_points_container.addView(point);
}
}
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
}
@Override
public void onPageSelected(int position) {
int realPosition = 0;
if (bannerPagerAdapter.getDataRealSize() != 0) {
realPosition = position % bannerPagerAdapter.getDataRealSize();
}
for (int i = 0; i < ll_main_points_container.getChildCount(); i++) {
View point = ll_main_points_container.getChildAt(i);
if (realPosition != i) {//未播放到的图片,它对应的小圆点是白色
point.setBackgroundResource(R.drawable.point_normal_shape);
point.getBackground().setAlpha(POINT_NORMAL_ALPHA);
} else {//当前播放到的图片,它对应的小圆点是橙色
point.setBackgroundResource(R.drawable.point_selected_shape);
}
}
}
@Override
public void onPageScrollStateChanged(int state) {
}
}
自动轮播我们用一个Hander实现,不断地postDelayed,这个大家可以去了解下安卓的消息机制。然后是监听翻页接口ViewPager.OnPagChangeListener,重写它的几个方法中,onPageSelected(int position)这里可以获取当前翻到了哪一页,然后将它对应的小圆点突出显示为橙色,否则就是白色半透明。