I. principle
First of all, put these pictures and some text to be rotated in different data sets. When the program starts, a set of pictures and text data will be displayed by default, and then a timer will be started to replace the displayed pictures and text data every other period of time. At the same time, some animation effects will be added to achieve the effect of rotation. At the same time, we also need to achieve the effect of rotating the pictures by sliding the fingers.
Two, implementation
1. Program start interface MainActivity
public class MainActivity extends AppCompatActivity implements ImageBannerFramLayout.FramLayoutLisenner{ private ImageBannerFramLayout mGroup; private int[] ids = new int[] { R.drawable.i1,//Picture resource 1 R.drawable.i2,//Picture resource 2 }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //Calculate the current phone width 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,"Index value = " + pos,Toast.LENGTH_SHORT).show(); } }
2. Create two new classes under new package view
1) New imagebarnerviewgroup class inherits from ViewGroup
public class ImageBarnnerViewGroup extends ViewGroup { private int children;//Total number of subviews of our View Group private int childwidth;//Width of subview private int childheight;//Height of subview private int x;//At this time, the value of x represents the abscissa of the first pressed position, and the abscissa of the position before each moving process private int index = 0;//Index for each image private Scroller scroller; /** * Use a click variable switch to judge, and judge that the user's operation is click at the moment of leaving the screen */ private boolean isClick;//Click event when true, not click event when 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 represents the specific index value of our current image } /** * To achieve the effect of circle point switching at the bottom of the rotation chart * Customize a layout inherited from fragmenlayout, and take advantage of FragmeLayout layout features */ //Automatic wheel broadcasting private boolean isAuto = true;//Turn on carousel by default 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://We need automatic rotation of pictures if (++index >= children) {//If it's the last picture, start with the first one index = 0; } scrollTo(childwidth * index,0); barnnerViewGroupLisnner.selectImage(index); break; default: } } }; private void startAuto() { isAuto = true; } private void stopAuto() { isAuto = false; } /** * Use Timer, TimerTask and Handler to realize automatic rotation */ 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) {//Turn on the carousel autohandler.sendEmptyMessage(0); } } }; timer.schedule(timerTask,100,3000); } @Override public void computeScroll() { super.computeScroll(); if (scroller.computeScrollOffset()) { scrollTo(scroller.getCurrX(),0); invalidate();//Repaint } } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //1. Find the number of subviews children = getChildCount();//We can know the number of self attempts if (0 == children) { setMeasuredDimension(0,0); } else { measureChildren(widthMeasureSpec, heightMeasureSpec); //At this time, we take the first subview = as the benchmark, that is, our View Group View view = getChildAt(0); childwidth = view.getMeasuredWidth(); childheight = view.getMeasuredHeight(); int width = view.getMeasuredWidth() * children; setMeasuredDimension(width,childheight); } //2. Measure the width and height of the subview //3. Calculate the width and height of the ViewGroup according to the gambling and height of the subview } @Override public boolean onInterceptTouchEvent(MotionEvent ev) { return super.onInterceptTouchEvent(ev); } /** * Two ways to realize the manual rotation of the rotation chart * 1,Using scrollTo and scrollBy to complete the manual rotation of the rotation chart * 1,Using the Scroller object to complete the manual effect of the rotation chart * @param event * @return */ @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN://Indicates the moment the user presses stopAuto();//Stop picture rotation if (!scroller.isFinished()) { scroller.abortAnimation(); } isClick = true; x=(int)event.getX(); break; case MotionEvent.ACTION_MOVE://Indicates the process of moving the user on the screen after pressing int moveX = (int) event.getX(); int distance = moveX - x; scrollBy(-distance,0); x = moveX; isClick = false; break; case MotionEvent.ACTION_UP://It marks the moment when the user lifts up int scrollX = getScrollX(); index = (scrollX + childwidth / 2) / childwidth; if (index < 0) { //It's sliding to the far left index = 0; } else if (index > children - 1) {//The description has slipped to the far right index = children - 1; } if (isClick) { //Click events lister.chickImageIndex(index); } else { int dx = index * childwidth - scrollX; scroller.startScroll(scrollX,0,dx,0); postInvalidate(); barnnerViewGroupLisnner.selectImage(index); } startAuto();//Turn on picture carousel break; default: } return true; //The purpose of returning true is to tell the parent View of the View Group container that we have handled the event } @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) New imagebannerframelayout class inherits from FrameLayout to implement two interfaces
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); } //Initialize the core class of custom image carousel function 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);//Pass Linsner to Framlayout imageBarnnerViewGroup.setLister(this); addView(imageBarnnerViewGroup); } //Initialize bottom dot layout 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. Create two new drawable resource files, dot_normal.xml and dot_select.xml, to realize the small dots at the bottom of the rotation chart
The difference is that the former is white and the latter is black
<?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>