Android实战简易教程<四十八>(App引导页面效果实现)

经常使用APP的童鞋会发现,第一次进入APP会有引导页面,里面可以放一些APP的使用介绍或其他信息等等,下面我们研究一下如何实现这个功能,增加APP的体验。

一、自定义控件继承ViewGroup:

[java]  view plain copy
  1. package com.genius.scroll;  
  2.   
  3. import android.content.Context;  
  4. import android.content.Intent;  
  5. import android.content.SharedPreferences;  
  6. import android.util.AttributeSet;  
  7. import android.util.Log;  
  8. import android.view.MotionEvent;  
  9. import android.view.VelocityTracker;  
  10. import android.view.View;  
  11. import android.view.ViewGroup;  
  12. import android.widget.Scroller;  
  13.   
  14. import com.genius.demo.MainActivity;  
  15.   
  16. public class MyScrollLayout extends ViewGroup {  
  17.   
  18.     private static final String TAG = "MyScrollLayout";  
  19.   
  20.     /** 用于判断甩动手势 **/  
  21.     private VelocityTracker mVelocityTracker;  
  22.   
  23.     private static final int SNAP_VELOCITY = 600;  
  24.   
  25.     /** 滑动控制器 **/  
  26.     private Scroller mScroller;  
  27.   
  28.     private int mCurScreen;  
  29.   
  30.     private int mDefaultScreen = 0;  
  31.   
  32.     private float mLastMotionX;  
  33.   
  34.     /** 当前页码 **/  
  35.     private int currentPage;  
  36.   
  37.     /** 总页码 **/  
  38.     private int pagesize;  
  39.   
  40.     private Context mContext;// 上下文对象  
  41.   
  42.     private OnViewChangeListener mOnViewChangeListener;// View滚动监听器  
  43.   
  44.     /** 标注是否跳转到主界面了 **/  
  45.     private boolean go_main = false;  
  46.   
  47.     private SharedPreferences preferences;  
  48.   
  49.     public MyScrollLayout(Context context) {  
  50.         super(context);  
  51.         this.mContext = context;  
  52.         init(context);  
  53.     }  
  54.   
  55.     public MyScrollLayout(Context context, AttributeSet attrs) {  
  56.         super(context, attrs);  
  57.         this.mContext = context;  
  58.         init(context);  
  59.     }  
  60.   
  61.     public MyScrollLayout(Context context, AttributeSet attrs, int defStyle) {  
  62.         super(context, attrs, defStyle);  
  63.         this.mContext = context;  
  64.         init(context);  
  65.     }  
  66.   
  67.     /** 
  68.      * 获取当前页码 
  69.      *  
  70.      * @param page 
  71.      */  
  72.     public void setPosition(int page) {  
  73.         if (page > 0) {  
  74.             currentPage = page;  
  75.         }  
  76.     }  
  77.   
  78.     /** 
  79.      * 获取总页数 
  80.      *  
  81.      * @param size 
  82.      */  
  83.     public void setPageSize(int size) {  
  84.         pagesize = size;  
  85.     }  
  86.   
  87.     private void init(Context context) {  
  88.         mCurScreen = mDefaultScreen;  
  89.   
  90.         mScroller = new Scroller(context);  
  91.     }  
  92.   
  93.     /** 
  94.      * 调用场景:在view给其孩子设置尺寸和位置时被调用 参数说明: 参数一:view有新的尺寸或位置; 参数二:相对于父view的Left位置; 
  95.      * 参数三:相对于父view的Top位置; 参数四:相对于父view的Right位置; 参数五:相对于父view的Bottom位置. 
  96.      */  
  97.     @Override  
  98.     protected void onLayout(boolean changed, int l, int t, int r, int b) {  
  99.         if (changed) {// 如果有新的尺寸或位置  
  100.             int childLeft = 0;  
  101.             final int childCount = getChildCount();// 返回子View的总数  
  102.   
  103.             for (int i = 0; i < childCount; i++) {// 遍历子View  
  104.                 final View childView = getChildAt(i);  
  105.                 if (childView.getVisibility() != View.GONE) {  
  106.   
  107.                     // childView.getMeasuredWidth()對View上的內容進行測量後得到的View內容佔據的寬度,前提是你必須在父佈局的  
  108.                     // onLayout()方法或者此View的onDraw()方法裡調用measure(0,0);(measure  
  109.                     // 參數的值你可以自己定義),否則你得到的結果和getWidth()得到的結果一樣  
  110.                     final int childWidth = childView.getMeasuredWidth();  
  111.   
  112.                     // 参数(相对于父布局的左、上、右、下的位置)  
  113.                     childView.layout(childLeft, 0, childLeft + childWidth,  
  114.                             childView.getMeasuredHeight());  
  115.   
  116.                     childLeft += childWidth;  
  117.                 }  
  118.             }  
  119.         }  
  120.     }  
  121.   
  122.     /** 
  123.      * 指明控件可获得的空间以及关于这个空间描述的元数据. 
  124.      */  
  125.     @Override  
  126.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  127.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  128.   
  129.         // MeasureSpec封装了父布局传递给子布局的布局要求,每个MeasureSpec代表了一组宽度和高度的要求。一个MeasureSpec由大小和模式组成  
  130.         final int width = MeasureSpec.getSize(widthMeasureSpec);// 根据提供的测量值提取大小值  
  131.         final int widthMode = MeasureSpec.getMode(widthMeasureSpec);// 根据提供的测量值(格式)提取模式(有三种模式)  
  132.         Log.d(TAG, "onMeasure width:" + width + " widthMode:" + widthMode);  
  133.   
  134.         final int count = getChildCount();// 获取子视图总数  
  135.   
  136.         for (int i = 0; i < count; i++) {  
  137.             // 调用子视图  
  138.             getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  139.         }  
  140.   
  141.         scrollTo(mCurScreen * width, 0);  
  142.   
  143.     }  
  144.   
  145.     public void snapToDestination() {  
  146.         final int screenWidth = getWidth();  
  147.   
  148.         final int destScreen = (getScrollX() + screenWidth / 2) / screenWidth;  
  149.         snapToScreen(destScreen);  
  150.     }  
  151.   
  152.     public void snapToScreen(int whichScreen) {  
  153.   
  154.         // 得到有效的页面布局  
  155.         whichScreen = Math.max(0, Math.min(whichScreen, getChildCount() - 1));  
  156.         if (getScrollX() != (whichScreen * getWidth())) {  
  157.   
  158.             final int delta = whichScreen * getWidth() - getScrollX();  
  159.   
  160.             mScroller.startScroll(getScrollX(), 0, delta, 0,  
  161.                     Math.abs(delta) * 2);  
  162.   
  163.             mCurScreen = whichScreen;  
  164.             invalidate(); // 重绘布局  
  165.   
  166.             if (mOnViewChangeListener != null) {  
  167.                 mOnViewChangeListener.OnViewChange(mCurScreen);  
  168.             }  
  169.         }  
  170.     }  
  171.   
  172.     /** 
  173.      * View绘制流程draw()中会调用 
  174.      */  
  175.     @Override  
  176.     public void computeScroll() {  
  177.         if (mScroller.computeScrollOffset()) {// 如果返回true,表示动画还没有结束  
  178.             scrollTo(mScroller.getCurrX(), mScroller.getCurrY());// 产生平滑的动画效果,根据当前偏移量,每次滚动一点  
  179.             postInvalidate();// 此时同样也需要刷新View ,否则效果可能有误差  
  180.         } else {// 如果返回false,表示startScroll完成  
  181.             Log.i(TAG, "scoller has finished");  
  182.         }  
  183.     }  
  184.   
  185.     @Override  
  186.     public boolean onTouchEvent(MotionEvent event) {  
  187.   
  188.         final int action = event.getAction();  
  189.         final float x = event.getX();  
  190.         final float y = event.getY();  
  191.         Log.d(TAG, "X:" + x + " Y:" + y);  
  192.   
  193.         float oldx = 0;  
  194.         switch (action) {  
  195.         case MotionEvent.ACTION_DOWN:  
  196.             oldx = event.getRawX();  
  197.             Log.i("""onTouchEvent  ACTION_DOWN");  
  198.   
  199.             if (mVelocityTracker == null) {  
  200.                 mVelocityTracker = VelocityTracker.obtain();  
  201.                 mVelocityTracker.addMovement(event);  
  202.             }  
  203.   
  204.             if (!mScroller.isFinished()) {  
  205.                 mScroller.abortAnimation();  
  206.             }  
  207.   
  208.             mLastMotionX = x;  
  209.             break;  
  210.   
  211.         case MotionEvent.ACTION_MOVE:  
  212.             int deltaX = (int) (mLastMotionX - x);  
  213.             float newX = event.getRawX();  
  214.   
  215.             /** 
  216.              * 最后一页跳转  
  217.              */  
  218.             if (newX - oldx > 3) {  
  219.   
  220.                 if (currentPage == pagesize - 1 && !go_main) {  
  221.                     go_main = true;  
  222.   
  223.                     preferences = mContext.getSharedPreferences("setting"0);  
  224.                     SharedPreferences.Editor editor = preferences.edit();  
  225.                     editor.putBoolean("isOpen"true);  
  226.                     editor.commit();  
  227.   
  228.                     Intent intent = new Intent();  
  229.                     intent.setClass(mContext, MainActivity.class);//跳转到第一个页面;  
  230.                     mContext.startActivity(intent);  
  231.                 }  
  232.             }  
  233.             if (IsCanMove(deltaX)) {  
  234.                 if (mVelocityTracker != null) {  
  235.                     mVelocityTracker.addMovement(event);  
  236.                 }  
  237.   
  238.                 mLastMotionX = x;  
  239.   
  240.                 scrollBy(deltaX, 0);  
  241.             }  
  242.   
  243.             break;  
  244.   
  245.         case MotionEvent.ACTION_UP:  
  246.   
  247.             int velocityX = 0;  
  248.             if (mVelocityTracker != null) {  
  249.                 mVelocityTracker.addMovement(event);  
  250.                 mVelocityTracker.computeCurrentVelocity(1000);  
  251.                 velocityX = (int) mVelocityTracker.getXVelocity();  
  252.             }  
  253.   
  254.             if (velocityX > SNAP_VELOCITY && mCurScreen > 0) {  
  255.                 // 向左移动  
  256.                 Log.e(TAG, "snap left");  
  257.                 snapToScreen(mCurScreen - 1);  
  258.             } else if (velocityX < -SNAP_VELOCITY  
  259.                     && mCurScreen < getChildCount() - 1) {  
  260.                 // 向右移动  
  261.                 Log.e(TAG, "snap right");  
  262.                 snapToScreen(mCurScreen + 1);  
  263.             } else {  
  264.                 snapToDestination();  
  265.             }  
  266.   
  267.             if (mVelocityTracker != null) {  
  268.                 mVelocityTracker.recycle();  
  269.                 mVelocityTracker = null;  
  270.             }  
  271.   
  272.             break;  
  273.         }  
  274.   
  275.         return true;  
  276.     }  
  277.   
  278.     private boolean IsCanMove(int deltaX) {  
  279.   
  280.         if (getScrollX() <= 0 && deltaX < 0) {  
  281.             return false;  
  282.         }  
  283.   
  284.         if (getScrollX() >= (getChildCount() - 1) * getWidth() && deltaX > 0) {  
  285.             return false;  
  286.         }  
  287.   
  288.         return true;  
  289.     }  
  290.   
  291.     public void SetOnViewChangeListener(OnViewChangeListener listener) {  
  292.         mOnViewChangeListener = listener;  
  293.     }  
  294.   
  295. //  /**  
  296. //   * 判断是否开启索引  
  297. //   * @return  
  298. //   */  
  299. //  private boolean isOpean(){  
  300. //        
  301. //  }  
  302.       
  303. }  

二、定义接口

[java]  view plain copy
  1. package com.genius.scroll;  
  2.   
  3. public interface OnViewChangeListener {  
  4.     public void OnViewChange(int view);  
  5. }  

三、创建实例

1.创建ViewPagerAdapter.java:
[java]  view plain copy
  1. package com.genius.demo;  
  2.   
  3. import java.util.List;  
  4.   
  5. import android.os.Parcelable;  
  6. import android.support.v4.view.PagerAdapter;  
  7. import android.support.v4.view.ViewPager;  
  8. import android.view.View;  
  9.   
  10. /** 
  11.  * ViewPgageAdapter适配器 
  12.  * @author yayun  
  13.  * 
  14.  */  
  15. public class ViewPageAdapter extends PagerAdapter {  
  16.   
  17.     List<View> mViewList;  
  18.   
  19.     public ViewPageAdapter(List<View> viewList) {  
  20.         mViewList = viewList;  
  21.     }  
  22.   
  23.     @Override  
  24.     public int getCount() {  
  25.         if (mViewList != null) {  
  26.             return mViewList.size();  
  27.         }  
  28.   
  29.         return 0;  
  30.     }  
  31.   
  32.     @Override  
  33.     public Object instantiateItem(View view, int index) {  
  34.         ((ViewPager) view).addView(mViewList.get(index), 0);  
  35.   
  36.         return mViewList.get(index);  
  37.     }  
  38.   
  39.     @Override  
  40.     public void destroyItem(View view, int position, Object arg2) {  
  41.   
  42.         ((ViewPager) view).removeView(mViewList.get(position));  
  43.     }  
  44.   
  45.     @Override  
  46.     public void finishUpdate(View arg0) {  
  47.   
  48.     }  
  49.   
  50.     @Override  
  51.     public boolean isViewFromObject(View view, Object obj) {  
  52.         return (view == obj);  
  53.   
  54.     }  
  55.   
  56.     @Override  
  57.     public void restoreState(Parcelable arg0, ClassLoader arg1) {  
  58.   
  59.     }  
  60.   
  61.     @Override  
  62.     public Parcelable saveState() {  
  63.         return null;  
  64.     }  
  65.   
  66.     @Override  
  67.     public void startUpdate(View arg0) {  
  68.   
  69.     }  
  70.   
  71. }  

2.创建SwitchViewDemoActivity.java:
[java]  view plain copy
  1. package com.genius.demo;  
  2.   
  3. import android.app.Activity;  
  4. import android.os.Bundle;  
  5. import android.view.View;  
  6. import android.view.View.OnClickListener;  
  7. import android.widget.ImageView;  
  8. import android.widget.LinearLayout;  
  9.   
  10. import com.genius.scroll.MyScrollLayout;  
  11. import com.genius.scroll.OnViewChangeListener;  
  12.   
  13. public class SwitchViewDemoActivity extends Activity implements  
  14.         OnViewChangeListener, OnClickListener {  
  15.   
  16.     private MyScrollLayout mScrollLayout;  
  17.   
  18.     private ImageView[] mImageViews;  
  19.   
  20.     private int mViewCount;  
  21.   
  22.     private int mCurSel;  
  23.       
  24.     /** Activity对象 **/  
  25.     public static Activity MY_ACTIVITY;  
  26.       
  27.     @Override  
  28.     public void onCreate(Bundle savedInstanceState) {  
  29.         super.onCreate(savedInstanceState);  
  30.         setContentView(R.layout.main);  
  31.           
  32.         MY_ACTIVITY = this;  
  33.           
  34.         init();  
  35.     }  
  36.   
  37.     private void init() {  
  38.         mScrollLayout = (MyScrollLayout) findViewById(R.id.ScrollLayout);  
  39.   
  40.         LinearLayout linearLayout = (LinearLayout) findViewById(R.id.llayout);  
  41.   
  42.         mViewCount = mScrollLayout.getChildCount();  
  43.         mImageViews = new ImageView[mViewCount];  
  44.   
  45.         for (int i = 0; i < mViewCount; i++) {  
  46.             mImageViews[i] = (ImageView) linearLayout.getChildAt(i);  
  47.             mImageViews[i].setEnabled(true);  
  48.             mImageViews[i].setOnClickListener(this);  
  49.             mImageViews[i].setTag(i);  
  50.         }  
  51.   
  52.         mScrollLayout.setPageSize(mImageViews.length);  
  53.         mCurSel = 0;  
  54.         mImageViews[mCurSel].setEnabled(false);  
  55.   
  56.         mScrollLayout.SetOnViewChangeListener(this);  
  57.     }  
  58.   
  59.     private void setCurPoint(int index) {  
  60.         if (index < 0 || index > mViewCount - 1 || mCurSel == index) {  
  61.             return;  
  62.         }  
  63.           
  64.         mImageViews[mCurSel].setEnabled(true);  
  65.         mImageViews[index].setEnabled(false);  
  66.         mScrollLayout.setPosition(index);  
  67.         mCurSel = index;  
  68.     }  
  69.   
  70.     @Override  
  71.     public void OnViewChange(int view) {  
  72.         setCurPoint(view);  
  73.     }  
  74.   
  75.     @Override  
  76.     public void onClick(View v) {  
  77.         int pos = (Integer) (v.getTag());  
  78.         setCurPoint(pos);  
  79.         mScrollLayout.snapToScreen(pos);  
  80.     }  
  81. }  

3.布局文件:
[java]  view plain copy
  1. <?xml version="1.0" encoding="utf-8"?>      
  2. <RelativeLayout   
  3.     android:layout_width="fill_parent"   
  4.     android:layout_height="fill_parent"  
  5.     android:id="@+id/touch"  
  6.     xmlns:android="http://schemas.android.com/apk/res/android">  
  7.       
  8.       
  9.     <com.genius.scroll.MyScrollLayout      
  10.       xmlns:android="http://schemas.android.com/apk/res/android"      
  11.       android:id="@+id/ScrollLayout"      
  12.       android:layout_width="fill_parent"      
  13.       android:layout_height="fill_parent">      
  14.     
  15.       <FrameLayout      
  16.       android:background="@drawable/guide01"      
  17.       android:layout_width="fill_parent"      
  18.       android:layout_height="fill_parent">  
  19.       </FrameLayout>     
  20.         
  21.       <FrameLayout      
  22.       android:background="@drawable/guide02"      
  23.       android:layout_width="fill_parent"      
  24.       android:layout_height="fill_parent">  
  25.       </FrameLayout>      
  26.             
  27.       <FrameLayout       
  28.       android:background="@drawable/guide03"       
  29.       android:layout_width="fill_parent"      
  30.       android:layout_height="fill_parent">      
  31.         
  32.   
  33.         
  34.       </FrameLayout>      
  35.         
  36.       <FrameLayout      
  37.       android:background="@drawable/guide04"      
  38.       android:layout_width="fill_parent"      
  39.       android:layout_height="fill_parent">      
  40.       </FrameLayout>      
  41.         
  42.       <FrameLayout      
  43.       android:background="@drawable/guide05"      
  44.       android:layout_width="fill_parent"      
  45.       android:layout_height="fill_parent">      
  46.       </FrameLayout>      
  47.          
  48.     </com.genius.scroll.MyScrollLayout>   
  49.   
  50.     <LinearLayout   
  51.         android:orientation="horizontal"   
  52.         android:id="@+id/llayout"   
  53.         android:layout_width="wrap_content"   
  54.         android:layout_height="wrap_content"   
  55.         android:layout_marginBottom="24.0dip"   
  56.         android:layout_alignParentBottom="true"   
  57.         android:layout_centerHorizontal="true">  
  58.           
  59.         <ImageView android:clickable="true"  android:padding="15.0dip" android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/guide_round" />  
  60.         <ImageView android:clickable="true"  android:padding="15.0dip"  android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/guide_round" />  
  61.         <ImageView android:clickable="true"  android:padding="15.0dip"  android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/guide_round" />  
  62.         <ImageView android:clickable="true"  android:padding="15.0dip"  android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/guide_round" />  
  63.         <ImageView android:clickable="true"  android:padding="15.0dip"  android:layout_gravity="center_vertical" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/guide_round" />  
  64.     </LinearLayout>  
  65.       
  66. </RelativeLayout>  

四、运行实例:




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值