This is the second blog in the Custom View series. Let's continue to learn about Custom View.
Today, let's implement the ad banner case.
We want to achieve such an effect.
To achieve this effect, we can use the ViewPager control, and then add some custom controls to complete. So let's start now.
Create a new android project.
Modify the activity_main.xml file.
<?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="com.itcast.test0429.MainActivity"> <android.support.v4.view.ViewPager android:id="@+id/viewpager" android:layout_width="match_parent" android:layout_height="180dp"/> <LinearLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignBottom="@id/viewpager" android:background="#44000000" android:orientation="vertical" android:padding="5dp"> <TextView android:id="@+id/tv_title" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:padding="3dp" android:text="Avengers Alliance 4" android:textColor="#ffffff" /> <LinearLayout android:id="@+id/ll_point_group" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_horizontal" android:orientation="horizontal"> </LinearLayout> </LinearLayout> </RelativeLayout>
Then modify the MainActivity code.
package com.itcast.test0429; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import butterknife.BindInt; import butterknife.BindView; import butterknife.ButterKnife; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @BindView(R.id.viewpager) ViewPager viewpager; @BindView(R.id.tv_title) TextView tvTitle; @BindView(R.id.ll_point_group) LinearLayout llPointGroup; private ArrayList<ImageView> imageViews; //Image Resource ID private final int[] imageIds = { R.drawable.b1, R.drawable.b2, R.drawable.b3 }; //Picture Title Collection private final String[] imageDescriptions = { "Title I", "Title II", "Title III" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); imageViews = new ArrayList<>(); for(int i = 0;i < imageIds.length;i++){ ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imageIds[i]); //Add to the collection imageViews.add(imageView); } //Setting up the adapter viewpager.setAdapter(new MyAdapter()); } class MyAdapter extends PagerAdapter{ /** * Total number of pictures obtained * @return */ @Override public int getCount() { return imageViews.size(); } /** * Equivalent to getView method * @param container ViewPager Oneself * @param position Location of the current instantiated page * @return */ @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = imageViews.get(position); container.addView(imageView);//Add to ViewPager Log.e(TAG,"instantiateItem==" + position + ",---imageView==" + imageView); return imageView; } /** * Compare view and object with the same instance * @param view page * @param object instantiateItem Method returns results * @return */ @Override public boolean isViewFromObject(View view, Object object) { return view == object; } /** * Releasing resources * @param container ViewPager * @param position Location to be released * @param object Pages to be released */ @Override public void destroyItem(ViewGroup container, int position, Object object) { Log.e(TAG,"destroyItem==" + position + ",---object==" + object); container.removeView((View) object); } } }
Note the use of PageAdapter. I've commented on each method. You should understand it. ViewPager initializes two pages after running, up to three. As the number of pages increases, ViewPager automatically destroys the front pages and then provides them to the back pages for use. This is the content optimization of ViewPage. We can verify that I print logs in both initialization and destruction methods. . Now let's run the project.
Let's look at the log.
Only two initialization messages were printed, indicating that ViewPager initialized only two pages.
We slide ViewPager to the left to switch pages and watch the log information.
You will find that after creating three instances, the instance of the first page is destroyed, which confirms the conclusion just made.
This completes our first stage of coding. Next, we implement adding pointers and setting text according to page changes.
There are many ways to implement the pointer, which can be displayed by pictures or drawn by myself. I use the second way. Post the code for MainActivity.
package com.itcast.test0429; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnPageChange; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @BindView(R.id.viewpager) ViewPager viewpager; @BindView(R.id.tv_title) TextView tvTitle; @BindView(R.id.ll_point_group) LinearLayout llPointGroup; private ArrayList<ImageView> imageViews; //Image Resource ID private final int[] imageIds = { R.drawable.b1, R.drawable.b2, R.drawable.b3, R.drawable.b1, R.drawable.b2, R.drawable.b3 }; /** * Last highlighted location */ private int prePosition = 0; //Picture Title Collection private final String[] imageDescriptions = { "Title I", "Title II", "Title III", "Title IV", "Title V", "Title VI" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); imageViews = new ArrayList<>(); for (int i = 0; i < imageIds.length; i++) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imageIds[i]); //Add to the collection imageViews.add(imageView); //Addition Points ImageView point = new ImageView(this); point.setBackgroundResource(R.drawable.point_selector); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(8, 8); if (i == 0) { point.setEnabled(true);//Show red } else { point.setEnabled(false);//Display grey params.leftMargin = 8; } point.setLayoutParams(params); llPointGroup.addView(point); } //Setting up the adapter viewpager.setAdapter(new MyAdapter()); tvTitle.setText(imageDescriptions[prePosition]); //Setting up to listen for changes to ViewPager pages viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { /** * Callback this method when the page scrolls * @param position Location of the current page * @param positionOffset Percentage of sliding pages * @param positionOffsetPixels Pixels sliding on the screen */ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } /** * Callback this method when a page is selected * @param position Location of the selected page */ @Override public void onPageSelected(int position) { //Setting text information for corresponding pages tvTitle.setText(imageDescriptions[position]); //Set the previous highlight to default - Grey llPointGroup.getChildAt(prePosition).setEnabled(false); //Currently set to highlight - red llPointGroup.getChildAt(position).setEnabled(true); prePosition = position; } /** * Callback this method when page scroll status changes * Still - "Sliding" * Sliding--Stillness * Quietness - "Dragging" * @param state */ @Override public void onPageScrollStateChanged(int state) { } }); } class MyAdapter extends PagerAdapter { /** * Total number of pictures obtained * * @return */ @Override public int getCount() { return imageViews.size(); } /** * Equivalent to getView method * * @param container ViewPager Oneself * @param position Location of the current instantiated page * @return */ @Override public Object instantiateItem(ViewGroup container, int position) { ImageView imageView = imageViews.get(position); container.addView(imageView);//Add to ViewPager Log.e(TAG, "instantiateItem==" + position + ",---imageView==" + imageView); return imageView; } /** * Compare view and object with the same instance * * @param view page * @param object instantiateItem Method returns results * @return */ @Override public boolean isViewFromObject(View view, Object object) { return view == object; } /** * Releasing resources * * @param container ViewPager * @param position Location to be released * @param object Pages to be released */ @Override public void destroyItem(ViewGroup container, int position, Object object) { Log.e(TAG, "destroyItem==" + position + ",---object==" + object); container.removeView((View) object); } } }
The point_selecotr.xml file code is as follows.
<?xml version="1.0" encoding="utf-8"?> <selector xmlns:android="http://schemas.android.com/apk/res/android"> <item android:state_enabled="false" android:drawable="@drawable/point_normal"/> <item android:state_enabled="true" android:drawable="@drawable/point_press"/> </selector>
The point_normal.xml file code is as follows.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="8dp" android:height="8dp" /> <solid android:color="#44000000" /> </shape>
The point_press.xml file code is as follows.
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="oval"> <size android:width="8dp" android:height="8dp" /> <solid android:color="#ff0000" /> </shape>
We run the project and preview the results.
At this time, the content of the pointer and the text title changes with our sliding, so that our goal is achieved.
We achieve the third stage of demand, supporting infinite sliding left and right.
How can we achieve this requirement? The number of sliding pages is determined by the adapter's getCount method, so we return Integer.MAX_VALUE directly in the getCount method, which is the maximum value of int. This number is already very large, which can be said to be approximate to infinite sliding, but set such a large number, and our data is not so much. In order to avoid the problem of index crossing when sliding pages, we must model all the locations of pages and keep them within our limited data range, so that we can meet our needs. So let's modify MainActivity's code.
package com.itcast.test0429; import android.os.Bundle; import android.support.v4.view.PagerAdapter; import android.support.v4.view.ViewPager; import android.support.v7.app.AppCompatActivity; import android.util.Log; import android.view.View; import android.view.ViewGroup; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.TextView; import java.util.ArrayList; import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.OnPageChange; public class MainActivity extends AppCompatActivity { private static final String TAG = MainActivity.class.getSimpleName(); @BindView(R.id.viewpager) ViewPager viewpager; @BindView(R.id.tv_title) TextView tvTitle; @BindView(R.id.ll_point_group) LinearLayout llPointGroup; private ArrayList<ImageView> imageViews; //Image Resource ID private final int[] imageIds = { R.drawable.b1, R.drawable.b2, R.drawable.b3, R.drawable.b1, R.drawable.b2, R.drawable.b3 }; /** * Last highlighted location */ private int prePosition = 0; //Picture Title Collection private final String[] imageDescriptions = { "Title I", "Title II", "Title III", "Title IV", "Title V", "Title VI" }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ButterKnife.bind(this); imageViews = new ArrayList<>(); for (int i = 0; i < imageIds.length; i++) { ImageView imageView = new ImageView(this); imageView.setBackgroundResource(imageIds[i]); //Add to the collection imageViews.add(imageView); //Addition Points ImageView point = new ImageView(this); point.setBackgroundResource(R.drawable.point_selector); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(8, 8); if (i == 0) { point.setEnabled(true);//Show red } else { point.setEnabled(false);//Display grey params.leftMargin = 8; } point.setLayoutParams(params); llPointGroup.addView(point); } //Setting up the adapter viewpager.setAdapter(new MyAdapter()); tvTitle.setText(imageDescriptions[prePosition]); //Setting up to listen for changes to ViewPager pages viewpager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() { /** * Callback this method when the page scrolls * @param position Location of the current page * @param positionOffset Percentage of sliding pages * @param positionOffsetPixels Pixels sliding on the screen */ @Override public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) { } /** * Callback this method when a page is selected * @param position Location of the selected page */ @Override public void onPageSelected(int position) { int realPosition = position % imageViews.size(); //Setting text information for corresponding pages tvTitle.setText(imageDescriptions[realPosition]); //Set the previous highlight to default - Grey llPointGroup.getChildAt(prePosition).setEnabled(false); //Currently set to highlight - red llPointGroup.getChildAt(realPosition).setEnabled(true); prePosition = realPosition; } /** * Callback this method when page scroll status changes * Still - "Sliding" * Sliding--Stillness * Quietness - "Dragging" * @param state */ @Override public void onPageScrollStateChanged(int state) { } }); } class MyAdapter extends PagerAdapter { /** * Total number of pictures obtained * * @return */ @Override public int getCount() { return Integer.MAX_VALUE; } /** * Equivalent to getView method * * @param container ViewPager Oneself * @param position Location of the current instantiated page * @return */ @Override public Object instantiateItem(ViewGroup container, int position) { int realPosition = position % imageViews.size(); ImageView imageView = imageViews.get(realPosition); container.addView(imageView);//Add to ViewPager Log.e(TAG, "instantiateItem==" + position + ",---imageView==" + imageView); return imageView; } /** * Compare view and object with the same instance * * @param view page * @param object instantiateItem Method returns results * @return */ @Override public boolean isViewFromObject(View view, Object object) { return view == object; } /** * Releasing resources * * @param container ViewPager * @param position Location to be released * @param object Pages to be released */ @Override public void destroyItem(ViewGroup container, int position, Object object) { Log.e(TAG, "destroyItem==" + position + ",---object==" + object); container.removeView((View) object); } } }
That's all right. Let's run the project.
At first glance, it seems that there is no problem, but the program is bug gy, just so that we did not test it out, I will operate it again.
Did you find the problem? When I first entered the program, could the right slide not move? Since ViewPager defaults to start at 0, there are no other pages on the left, so you can't slide right. How can you solve this problem? Find out the reason for the problem, then there can be a solution, since there is no page on the left, then let it have pages, OK? If we position the first image in the middle, it will have a huge number of pages on the left and right. Although there are many pages, it is not endless. If there is a user, he is idle and panicky, he is desperately sliding. As a result, all the pages on the left or right are sliding out. In this case, we can only say that this person is really idle and panicky. In short, according to the normal situation, so many pages are enough for use. Household slides.
We know the principle, how to achieve it by coding? Simply, just add the following code after ViewPager sets up the adapter.
//Set the middle position int item = Integer.MAX_VALUE / 2 - Integer.MAX_VALUE / 2 % imageViews.size();//Make sure that imageViews are integer multiples viewpager.setCurrentItem(item);
Now run the project and preview the effect.
This will solve the problem. The whole case is over, which is only a small part of ViewPager's use. This program can also add many functions, such as automatic playback, click and jump, etc. Because of the limited space, I do not have to implement it, interested in writing by myself.
Source code has been uploaded to GitHub