Android User Guide Interface
First, I have stolen several pictures of the Super curriculum.
In many applications, almost every application has its own Splash User Guide interface, which is not displayed after the first startup of the user, mainly to show new functions to the user.
The analysis mainly uses ViewPager + Indicator to implement a circular Indicator. This circular Indicator inherits LinearLayout and needs some attributes to be customized, such as the color and size of the Indicator, margin and other indicators can also be automatically rolled. For example, if the indicator is circular in the place where the slides are displayed, we need to draw this circular indicator to implement ViewPager. onPageChangeListener interface to implement Custom Attributes
You can see the meaning of the attribute by name.
Custom variables are parsed from the layout file. In addition, if the layout file is not used, there should be a default constant.
Define default Constants
private static final int DEFAULT_CIRCLE_SPACING = 5; private static final int DEFAULT_CIRCLE_COLOR=Color.WHITE; private static final int DEFAULT_CIRCLE_SIZE=3; private static final boolean DEFAULT_CIRCLE_AUTO_SCROLL=false; private static final int DEFAULT_CIRCLE_SCROLL_DELAY_TIME=3000; private static final boolean DEFAULT_CIRCLE_SCROLL_ANIMATION=true;
Define variables used to store Custom Attributes
private int mSpacing; private int mSize; private int mFillColor; private int mStrokeColor; private boolean mAutoScroll; private int mDelayTime; private boolean mIsAnimation;
Define other auxiliary variables, such as Canvas, Bitmap, and Paint, to draw a circular indicator.
private static final int CIRCLE_STROKE_WIDTH =1; private static final int BITMAP_PADDING =2; private ViewPager mViewPager; private int mCount; private int mLastIndex = 0; private Canvas mCanvas; private Paint mPaint; private Bitmap mSelectBitmap; private Bitmap mUnselectBitmap;
Resolve custom attributes and assign values to corresponding variables
private void initCustomParams(Context context, AttributeSet attrs) { TypedArray typedArray = context.obtainStyledAttributes(attrs, R.styleable.CircleIndicator); try { mSpacing = typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_circle_spacing, DEFAULT_CIRCLE_SPACING); mFillColor=typedArray.getColor(R.styleable.CircleIndicator_circle_fill_color,DEFAULT_CIRCLE_COLOR); mStrokeColor=typedArray.getColor(R.styleable.CircleIndicator_circle_stroke_color,DEFAULT_CIRCLE_COLOR); mSize= typedArray.getDimensionPixelSize(R.styleable.CircleIndicator_circle_radius, DEFAULT_CIRCLE_SIZE); mAutoScroll= typedArray.getBoolean(R.styleable.CircleIndicator_circle_auto_scroll, DEFAULT_CIRCLE_AUTO_SCROLL); mDelayTime=typedArray.getInt(R.styleable.CircleIndicator_circle_scroll_delay_time,DEFAULT_CIRCLE_SCROLL_DELAY_TIME); mIsAnimation=typedArray.getBoolean(R.styleable.CircleIndicator_circle_scroll_animation,DEFAULT_CIRCLE_SCROLL_ANIMATION); } finally { typedArray.recycle(); } }
Our indicator is drawn by ourselves. Next we will draw a circular indicator.
private void init() { setOrientation(HORIZONTAL); mPaint = new Paint(); mPaint.setAntiAlias(true); mPaint.setDither(true); mPaint.setStyle(Paint.Style.FILL_AND_STROKE); mPaint.setStrokeWidth(dip2px(CIRCLE_STROKE_WIDTH)); mPaint.setColor(mFillColor); int size=dip2px(mSize+ BITMAP_PADDING + BITMAP_PADDING); int radius=dip2px(mSize / 2); int centerPoint=radius+ BITMAP_PADDING; mSelectBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); mUnselectBitmap = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888); mCanvas = new Canvas(); mCanvas.setBitmap(mSelectBitmap); mCanvas.drawCircle(centerPoint, centerPoint, radius, mPaint); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(mStrokeColor); mCanvas.setBitmap(mUnselectBitmap); mCanvas.drawCircle(centerPoint, centerPoint, radius, mPaint); }
Implements the constructor, finally calls the constructor of the three parameters, and calls the relevant functions for initialization.
public CircleIndicator(Context context) { this(context, null); } public CircleIndicator(Context context, AttributeSet attrs) { this(context, attrs, 0); } public CircleIndicator(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initCustomParams(context, attrs); init(); }
Implement indicator-related Logic
First, you need to initialize the position of the indicator. It should be the first page of ViewPager, that is, the initialization position is 0, initIndicator is called, and the background image of the indicator is set to the selected status. record the position of the last indicator, that is, the current position. if removeIndicator is removed from all the sub-views of the current class, updateIndicator needs to set the background image of the previous position to unselected, and the current position is not selected, record that the last position is the current position. addIndicator needs to pass in the number of circular indicators. The value is the number of ViewPager pages, create an ImageView, set the background image to the image when it is not selected, and set the margin, add it to the subview of the current class. If Automatic scrolling is set, you also need to perform the setViewPager function for initialization.
public void setViewPager(ViewPager viewPager) { mViewPager = viewPager; mViewPager.addOnPageChangeListener(this); if (mViewPager != null) { mCount = mViewPager.getAdapter().getCount(); addIndicator(mCount); } } private void addIndicator(int count) { removeIndicator(); if (count <= 0) return; for (int i = 0; i < count; i++) { ImageView imageView = new ImageView(getContext()); LayoutParams params = new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT); params.leftMargin = mSpacing/2; params.rightMargin = mSpacing/2; imageView.setImageBitmap(mUnselectBitmap); addView(imageView, params); } initIndicator(); if(mAutoScroll){ sendScrollMessage(mDelayTime); } } private void initIndicator() { ((ImageView) getChildAt(0)).setImageBitmap(mSelectBitmap); mLastIndex=0; } private void removeIndicator() { removeAllViews(); } private void updateIndicator(int position) { if (position != mLastIndex) { ((ImageView) getChildAt(mLastIndex)).setImageBitmap(mUnselectBitmap); ((ImageView) getChildAt(position)).setImageBitmap(mSelectBitmap); } mLastIndex = position; }
Implement automatic scrolling, mainly through Handler for latency implementation
private Handler mHandler=new Handler(){ @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case SCROLL_WHAT: scrollOnce(); sendScrollMessage(mDelayTime); break; } } }; public void scrollOnce() { PagerAdapter adapter = mViewPager.getAdapter(); if (adapter == null) { return; } int nextIndex=mViewPager.getCurrentItem(); ++nextIndex; if(nextIndex >=mCount){ nextIndex =0; } updateIndicator(nextIndex); mViewPager.setCurrentItem(nextIndex, mIsAnimation); } private void sendScrollMessage(long delayTimeInMills) { mHandler.removeMessages(SCROLL_WHAT); mHandler.sendEmptyMessageDelayed(SCROLL_WHAT, delayTimeInMills); }
Implement related getter and setter Functions
private void setAutoScroll(boolean autoScroll){ if (autoScroll){ sendScrollMessage(mDelayTime); }else{ mHandler.removeMessages(SCROLL_WHAT); } mAutoScroll=autoScroll; } public boolean isAutoScroll() { return mAutoScroll; } public int getDelayTime() { return mDelayTime; } public void setDelayTime(int delayTime) { mDelayTime = delayTime; } public boolean isAnimation() { return mIsAnimation; } public void setIsAnimation(boolean isAnimation) { mIsAnimation = isAnimation; }
Implement interface functions
@Override public void onPageScrolled(int i, float v, int i1) { } @Override public void onPageSelected(int position) { updateIndicator(position); } @Override public void onPageScrollStateChanged(int i) { }
And a tool function for unit conversion
private int dip2px(int dip) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getResources().getDisplayMetrics()); }
Use
private void initView() { mViewPager= (ViewPager) findViewById(R.id.viewpager); mCircleIndicator= (CircleIndicator) findViewById(R.id.circle_indicator); mViewPager.setAdapter(new FragmentPagerAdapter(getSupportFragmentManager()) { private int[] resId={R.mipmap.ic_help_view_1,R.mipmap.ic_help_view_2,R.mipmap.ic_help_view_3,R.mipmap.ic_help_view_4}; private Map
mFragments=new HashMap
(); @Override public Fragment getItem(int i) { Fragment fragment=mFragments.get(i); if(fragment==null){ fragment=BlankFragment.newInstance(resId[i],i,resId.length); mFragments.put(i,fragment); } return fragment; } @Override public int getCount() { return resId.length; } }); mCircleIndicator.setViewPager(mViewPager); }
package cn.edu.zafu.splash;import android.content.Intent;import android.os.Bundle;import android.support.v4.app.Fragment;import android.util.TypedValue;import android.view.LayoutInflater;import android.view.View;import android.view.ViewGroup;import android.view.WindowManager;import android.widget.ImageButton;import android.widget.ImageView;import android.widget.RelativeLayout;public class BlankFragment extends Fragment { private static final String IMAGE_ID = imageId; private static final String CUCRNT = curcent; private static final String TOTAL = total; private int mImageId; private int mCurcent; private int mTotal; public static BlankFragment newInstance(int imageId,int current,int total) { BlankFragment fragment = new BlankFragment(); Bundle args = new Bundle(); args.putInt(IMAGE_ID, imageId); args.putInt(CUCRNT, current); args.putInt(TOTAL, total); fragment.setArguments(args); return fragment; } public BlankFragment() { } @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (getArguments() != null) { mImageId = getArguments().getInt(IMAGE_ID); mCurcent = getArguments().getInt(CUCRNT); mTotal = getArguments().getInt(TOTAL); } } @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view= inflater.inflate(R.layout.fragment_blank, container, false); return view; } @Override public void onViewCreated(View view, Bundle savedInstanceState) { getActivity().getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_FULLSCREEN); super.onViewCreated(view, savedInstanceState); ImageView imageView= (ImageView) view.findViewById(R.id.image); imageView.setImageResource(mImageId); if(mCurcent==mTotal-1){ RelativeLayout relativeLayout= (RelativeLayout) view.findViewById(R.id.relativelayout); ImageButton button=new ImageButton(getActivity().getApplicationContext()); button.setBackgroundResource(R.drawable.last_button_selector); RelativeLayout.LayoutParams params=new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.WRAP_CONTENT,RelativeLayout.LayoutParams.WRAP_CONTENT); params.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM); params.addRule(RelativeLayout.CENTER_HORIZONTAL); params.bottomMargin=dip2px(80); relativeLayout.addView(button,params); button.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { int versionCode=Util.getAppVersionCode(getActivity()); Util.set(getActivity(),Util.FILE_NAME,versionCode+,true); Intent intent=new Intent(getActivity(),SecondActivity.class); startActivity(intent); getActivity().finish(); } }); } } private int dip2px(int dip) { return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dip, getActivity().getResources().getDisplayMetrics()); }}
If you want to enable the first startup or not, you need to add some logic judgment if it is displayed. If the current version number is persistent, skip it directly, this data is processed by clicking the event in the last button on the Splash page.
private boolean ignoreSplash() { if(Util.contatins(this, Util.FILE_NAME, Util.getAppVersionCode(this) + )){ Intent intent=new Intent(MainActivity.this,SecondActivity.class); startActivity(intent); this.finish(); return true; } return false; }
public void onClick(View v) { int versionCode=Util.getAppVersionCode(getActivity()); Util.set(getActivity(),Util.FILE_NAME,versionCode+,true); Intent intent=new Intent(getActivity(),SecondActivity.class); startActivity(intent); getActivity().finish(); }