现在的位置: 首页 > 综合 > 正文

Android中自定义属性的使用 Android中自定义属性的格式详解Android 滑动效果高级篇(八)—— 自定义控件

2017年12月12日 ⁄ 综合 ⁄ 共 25147字 ⁄ 字号 评论关闭

Android中自定义属性的使用

Posted on 2011-05-27 19:51 NCUT蓝色理想 阅读(4837) 评论(2编辑 收藏

做Android布局是件很享受的事,这得益于他良好的xml方式。使用xml可以快速有效的为软件定义界面。可是有时候我们总感觉官方定义的一些基本组件不够用,自定义组件就不可避免了。那么如何才能做到像官方提供的那些组件一样用xml来定义他的属性呢?现在我们就来讨论一下他的用法。

一、在res/values文件下定义一个attrs.xml文件,代码如下:

<?xml version="1.0" encoding="utf-8"?> 
<resources> 
    <declare-styleable name="ToolBar"> 
        <attr name="buttonNum" format="integer"/> 
        <attr name="itemBackground" format="reference|color"/> 
    </declare-styleable> 
</resources>

二、在布局xml中如下使用该属性:

<?xml version="1.0" encoding="utf-8"?> 
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" 
    xmlns:toolbar="http://schemas.android.com/apk/res/cn.zzm.toolbar" 
    android:orientation="vertical" 
    android:layout_width="fill_parent" 
    android:layout_height="fill_parent" 
    > 
    <cn.zzm.toolbar.ToolBar android:id="@+id/gridview_toolbar" 
        android:layout_width="fill_parent" 
        android:layout_height="wrap_content" 
        android:layout_alignParentBottom="true" 
        android:background="@drawable/control_bar" 
        android:gravity="center" 
        toolbar:buttonNum="5" 
        toolbar:itemBackground="@drawable/control_bar_item_bg"/> 
</RelativeLayout>

三、在自定义组件中,可以如下获得xml中定义的值:

TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ToolBar); 
buttonNum = a.getInt(R.styleable.ToolBar_buttonNum, 5); 
itemBg = a.getResourceId(R.styleable.ToolBar_itemBackground, -1);

a.recycle();

就这么简单的三步,即可完成对自定义属性的使用。

*********************************************************************

好了,基本用法已经讲完了,现在来看看一些注意点和知识点吧。

首先来看看attrs.xml文件。

该文件是定义属性名和格式的地方,需要用<declare-styleable name="ToolBar"></declare-styleable>包围所有属性。其中name为该属性集的名字,主要用途是标识该属性集。那在什么地方会用到呢?主要是在第三步。看到没?在获取某属性标识时,用到"R.styleable.ToolBar_buttonNum",很显然,他在每个属性前面都加了"ToolBar_"。

在来看看各种属性都有些什么类型吧:string , integer , dimension , reference , color , enum.

前面几种的声明方式都是一致的,例如:<attr name="buttonNum" format="integer"/>。 
只有enum是不同的,用法举例:

<attr name="testEnum"> 
    <enum name="fill_parent" value="-1"/> 
    <enum name="wrap_content" value="-2"/> 
</attr>

如果该属性可同时传两种不同的属性,则可以用“|”分割开即可。

 

让我们再来看看布局xml中需要注意的事项。

首先得声明一下:xmlns:toolbar=http://schemas.android.com/apk/res/cn.zzm.toolbar 
注意,“toolbar”可以换成其他的任何名字,后面的url地址必须最后一部分必须用上自定义组件的包名。自定义属性了,在属性名前加上“toolbar”即可。

 

最后来看看java代码中的注意事项。

在自定义组件的构造函数中,用

TypedArray a = context.obtainStyledAttributes(attrs,R.styleable.ToolBar);

来获得对属性集的引用,然后就可以用“a”的各种方法来获取相应的属性值了。这里需要注意的是,如果使用的方法和获取值的类型不对的话,则会返回默认值。因此,如果一个属性是带两个及以上不用类型的属性,需要做多次判断,知道读取完毕后才能判断应该赋予何值。当然,在取完值的时候别忘了回收资源哦!

Android中自定义属性的格式详解

分类: Android基础 5818人阅读 评论(3) 收藏 举报

1. reference:参考某一资源ID。

 

    (1)属性定义:

 

            <declare-styleable name = "名称">

                   <attr name = "background" format = "reference" />

            </declare-styleable>

 

    (2)属性使用:

 

             <ImageView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/图片ID"

                     />

 

2. color:颜色值。

 

    (1)属性定义:

 

            <declare-styleable name = "名称">

                   <attr name = "textColor" format = "color" />

            </declare-styleable>

 

    (2)属性使用:

 

            <TextView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:textColor = "#00FF00"

                     />

 

3. boolean:布尔值。

 

    (1)属性定义:

 

            <declare-styleable name = "名称">

                   <attr name = "focusable" format = "boolean" />

            </declare-styleable>

 

    (2)属性使用:

 

            <Button

                    android:layout_width = "42dip"
                    android:layout_height = "42dip"

                    android:focusable = "true"

                    />

 

4. dimension:尺寸值。

 

    (1)属性定义:

 

            <declare-styleable name = "名称">

                   <attr name = "layout_width" format = "dimension" />

            </declare-styleable>

 

    (2)属性使用:

 

            <Button

                    android:layout_width = "42dip"
                    android:layout_height = "42dip"

                    />

 

5. float:浮点值。

 

    (1)属性定义:

 

            <declare-styleable name = "AlphaAnimation">

                   <attr name = "fromAlpha" format = "float" />
                   <attr name = "toAlpha" format = "float" />

            </declare-styleable>

 

    (2)属性使用:

 

            <alpha
                   android:fromAlpha = "1.0"
                   android:toAlpha = "0.7"

                   />

 

6. integer:整型值。

 

    (1)属性定义:

 

            <declare-styleable name = "AnimatedRotateDrawable">

                   <attr name = "visible" />
                   <attr name = "frameDuration" format="integer" />
                   <attr name = "framesCount" format="integer" />
                   <attr name = "pivotX" />
                   <attr name = "pivotY" />
                   <attr name = "drawable" />

            </declare-styleable>

 

    (2)属性使用:

 

            <animated-rotate

                   xmlns:android = "http://schemas.android.com/apk/res/android"  
                   android:drawable = "@drawable/图片ID"  
                   android:pivotX = "50%"  
                   android:pivotY = "50%"  
                   android:framesCount = "12"  
                   android:frameDuration = "100"

                   />

 

7. string:字符串。

 

    (1)属性定义:

 

            <declare-styleable name = "MapView">
                   <attr name = "apiKey" format = "string" />
            </declare-styleable>

 

    (2)属性使用:

 

            <com.google.android.maps.MapView
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent"
                    android:apiKey = "0jOkQ80oD1JL9C6HAja99uGXCRiS2CGjKO_bc_g"

                    />

 

8. fraction:百分数。

 

    (1)属性定义:

 

            <declare-styleable name="RotateDrawable">
                   <attr name = "visible" />
                   <attr name = "fromDegrees" format = "float" />
                   <attr name = "toDegrees" format = "float" />
                   <attr name = "pivotX" format = "fraction" />
                   <attr name = "pivotY" format = "fraction" />
                   <attr name = "drawable" />
            </declare-styleable>

 

    (2)属性使用:

 

            <rotate

                   xmlns:android = "http://schemas.android.com/apk/res/android
               android:interpolator = "@anim/动画ID"

                   android:fromDegrees = "0" 
               android:toDegrees = "360"

                   android:pivotX = "200%"

                   android:pivotY = "300%
               android:duration = "5000"

                   android:repeatMode = "restart"

                   android:repeatCount = "infinite"

                   />

 

9. enum:枚举值。

 

    (1)属性定义:

 

            <declare-styleable name="名称">
                   <attr name="orientation">
                          <enum name="horizontal" value="0" />
                          <enum name="vertical" value="1" />
                   </attr>            

            </declare-styleable>

 

    (2)属性使用:

 

            <LinearLayout

                    xmlns:android = "http://schemas.android.com/apk/res/android"
                    android:orientation = "vertical"
                    android:layout_width = "fill_parent"
                    android:layout_height = "fill_parent"
                    >
            </LinearLayout>

 

10. flag:位或运算。

 

     (1)属性定义:

 

             <declare-styleable name="名称">
                    <attr name="windowSoftInputMode">
                            <flag name = "stateUnspecified" value = "0" />
                            <flag name = "stateUnchanged" value = "1" />
                            <flag name = "stateHidden" value = "2" />
                            <flag name = "stateAlwaysHidden" value = "3" />
                            <flag name = "stateVisible" value = "4" />
                            <flag name = "stateAlwaysVisible" value = "5" />
                            <flag name = "adjustUnspecified" value = "0x00" />
                            <flag name = "adjustResize" value = "0x10" />
                            <flag name = "adjustPan" value = "0x20" />
                            <flag name = "adjustNothing" value = "0x30" />
                     </attr>         

             </declare-styleable>

 

     (2)属性使用:

 

            <activity

                   android:name = ".StyleAndThemeActivity"
                   android:label = "@string/app_name"
                   android:windowSoftInputMode = "stateUnspecified | stateUnchanged | stateHidden">
                   <intent-filter>
                          <action android:name = "android.intent.action.MAIN" />
                          <category android:name = "android.intent.category.LAUNCHER" />
                   </intent-filter>
             </activity>

 

     注意:

 

     属性定义时可以指定多种类型值。

 

    (1)属性定义:

 

            <declare-styleable name = "名称">

                   <attr name = "background" format = "reference|color" />

            </declare-styleable>

 

    (2)属性使用:

 

             <ImageView

                     android:layout_width = "42dip"
                     android:layout_height = "42dip"
                     android:background = "@drawable/图片ID|#00FF00"

                     />

 

Android 滑动效果高级篇(八)—— 自定义控件

分类: Android 5650人阅读 评论(13) 收藏 举报

自定义控件,较常用View、ViewGroup、Scroller三个类,其继承关系如下:

本示例自定义控件,实现一个Gallery效果,并添加了一个显示View个数和位置的bar条,效果图:

自定义控件,包含通过继承实现的自定义控件和自定义控件属性两部分,即控件和属性

1、自定义属性

自定义属性,分为定义属性、解析属性、设置属性三部分,具体步骤:

首先,在res/valus/attrs.xml属性资源文件中,定义控件属性

  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="com.myapps.widget.Pager">  
  4.         <attr name="pageWidth" format="dimension" />  
  5.     </declare-styleable>  
  6.       
  7.     <declare-styleable name="com.myapps.widget.PagerBar">  
  8.         <attr name="barColor" format="color" />  
  9.         <attr name="highlightColor" format="color" />  
  10.         <attr name="fadeDelay" format="integer" />  
  11.         <attr name="fadeDuration" format="integer" />  
  12.         <attr name="roundRectRadius" format="dimension" />  
  13.     </declare-styleable>  
  14. </resources>  

然后,在自定义控件的代码中,解析自定义的属性,如在PagerBar.java:

  1. // 自定义属性  
  2.         TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);  
  3.         int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);              // bar背景色  
  4.         int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);    // bar前景色  
  5.         fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);             // bar消失延迟时间  
  6.         fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);    // bar消失动画时间  
  7.         ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);  
  8.         a.recycle();  

最后,在布局文件中设置属性,如在main.xml

  1. <com.homer.mycontrol.PagerBar  
  2.     android:id="@+id/control"  
  3.     android:layout_width="fill_parent"  
  4.     android:layout_height="4dip"  
  5.     android:layout_margin="8dip"  
  6.     myapps:roundRectRadius="2dip" />  <!-- 自定义圆角 -->  

其中,在布局中间main.xml中,需要注意:

xmlns:myapps="http://schemas.android.com/apk/res/com.homer.mycontrol"

定义属性时,在declare-styleable的name中,需要包含com.myapps.widget.PagerBar,表示自定义的控件PageBar是widget子类,myapps是xmlns解析标记

解析属性时,在TypedArray中,需要包含R.styleable.com_myapps_widget_PagerBar,横线替换了圆点.

定义属性时,在com.homer.mycontrol.PagerBar中,需要包含myapps:roundRectRadius="2dip",加上myapps解析标记

2、自定义控件PagerBar

自定义PagerBar,在图片下方用来显示图片滑到了第几页,即上面效果图(图2、图3)中的下部银白色细条,具体实现:

  1. public PagerBar(Context context, AttributeSet attrs, int defStyle) {  
  2.     super(context, attrs, defStyle);  
  3.   
  4.     // 自定义属性  
  5.     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_PagerBar);  
  6.     int barBackColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_barColor, DEFAULT_BAR_BACKCOLOR);              // bar背景色  
  7.     int barForeColor = a.getColor(R.styleable.com_myapps_widget_PagerBar_highlightColor, DEFAULT_BAR_FORECOLOR);    // bar前景色  
  8.     fadeDelay = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDelay, DEFAULT_FADE_DELAY);             // bar消失延迟时间  
  9.     fadeDuration = a.getInteger(R.styleable.com_myapps_widget_PagerBar_fadeDuration, DEFAULT_FADE_DURATION);    // bar消失动画时间  
  10.     ovalRadius = a.getDimension(R.styleable.com_myapps_widget_PagerBar_roundRectRadius, 2f);  
  11.     a.recycle();  
  12.   
  13.     barBackPaint = new Paint();  
  14.     barBackPaint.setColor(barBackColor);  
  15.   
  16.     barForePaint = new Paint();  
  17.     barForePaint.setColor(barForeColor);  
  18.   
  19.     fadeOutAnimation = new AlphaAnimation(1f, 0f);  
  20.     fadeOutAnimation.setDuration(fadeDuration);  
  21.     fadeOutAnimation.setRepeatCount(0);  
  22.     fadeOutAnimation.setInterpolator(new LinearInterpolator());  
  23.     fadeOutAnimation.setFillEnabled(true);  
  24.     fadeOutAnimation.setFillAfter(true);  
  25. }  
  26.   
  27. public int getNumPages() {  
  28.     return numPages;  
  29. }  
  30.   
  31. public void setNumPages(int numPages) {  
  32.     if (numPages <= 0) {  
  33.         throw new IllegalArgumentException("numPages must be positive");  
  34.     }  
  35.     this.numPages = numPages;  
  36.     invalidate();       // 重绘View  
  37.     fadeOut();          // 设置bar消失效果  
  38. }  
  39.   
  40. /** bar消失动画 */  
  41. private void fadeOut() {  
  42.     if (fadeDuration > 0) {  
  43.         clearAnimation();  
  44.         fadeOutAnimation.setStartTime(AnimationUtils.currentAnimationTimeMillis() + fadeDelay); //延迟fadeDelay后动画开始  
  45.         setAnimation(fadeOutAnimation);  
  46.     }  
  47. }  
  48.   
  49. /**  @return  0 to numPages-1 */  
  50. public int getCurrentPage() {  
  51.     return currentPage;  
  52. }  
  53.   
  54. /** @param currentPage  0 to numPages-1  */  
  55. public void setCurrentPage(int currentPage) {  
  56.     if (currentPage < 0 || currentPage >= numPages) {  
  57.         throw new IllegalArgumentException("currentPage parameter out of bounds");  
  58.     }  
  59.     if (this.currentPage != currentPage) {  
  60.         this.currentPage = currentPage;  
  61.         this.position = currentPage * getPageWidth();   // bar前景色滑动条的起始位置(像素值)  
  62.         invalidate();  
  63.         fadeOut();  
  64.     }  
  65. }  
  66.   
  67. /** 获取View的宽度,即bar的宽度 */  
  68. public int getPageWidth() {  
  69.     return getWidth() / numPages;   // getWidth()是PagerBar的宽度(减去了margin左右距离后)  
  70. }  
  71.   
  72. /**  @param position     can be -pageWidth to pageWidth*(numPages+1)  */  
  73. public void setPosition(int position) {  
  74.     if (this.position != position) {  
  75.         this.position = position;  
  76.         invalidate();  
  77.         fadeOut();  
  78.     }  
  79. }  
  80.   
  81. @Override  
  82. protected void onDraw(Canvas canvas) {  
  83.     canvas.drawRoundRect(new RectF(00, getWidth(), getHeight()), ovalRadius, ovalRadius, barBackPaint);   // 绘制bar背景  
  84.     canvas.drawRoundRect(new RectF(position, 0, position + (getWidth() / numPages), getHeight()), ovalRadius, ovalRadius, barForePaint);    // 绘制bar前景  
  85. }  

3、自定义控件Pager

自定义控件Pager,继承自ViewGroup,用来显示图片的,类似于Gallery,实现主要部分包含:

A、自定义属性解析

B、Pager容器控件Scroller滑动页设置与控制

C、容器状态保存(onSaveInstanceState)

D、容器事件监听接口

详细实现如下:

A、自定义属性解析

  1. public Pager(Context context, AttributeSet attrs, int defStyle) {  
  2.     super(context, attrs, defStyle);  
  3.   
  4.     // 自定义属性  
  5.     TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.com_myapps_widget_Pager);  
  6.     pageWidthSpec = a.getDimensionPixelSize(R.styleable.com_myapps_widget_Pager_pageWidth, SPEC_UNDEFINED);  
  7.     a.recycle();  
  8. }  

B、Pager容器控件Scroller滑动页设置与控制

  1. public void setCurrentPage(int currentPage) {  
  2.     mCurrentPage = Math.max(0, Math.min(currentPage, getChildCount()));     // 非常好  
  3.     scrollTo(getScrollXForPage(mCurrentPage), 0);  
  4.     invalidate();   // 重绘View  
  5. }  
  6.   
  7. int getCurrentPage() {  
  8.     return mCurrentPage;  
  9. }  
  10.   
  11. public void setPageWidth(int pageWidth) {  
  12.     this.pageWidthSpec = pageWidth;  
  13. }  
  14.   
  15. public int getPageWidth() {  
  16.     return pageWidth;  
  17. }  
  18.   
  19. /** 获取whichPage的Pager起始x位置,whichPage从0开始计 */  
  20. private int getScrollXForPage(int whichPage) {  
  21.     return (whichPage * pageWidth) - pageWidthPadding();  
  22. }  
  23.   
  24. /** 返回View的 paddingwidth 一半(1/2)*/  
  25. int pageWidthPadding() {  
  26.     return ((getMeasuredWidth() - pageWidth) / 2);  
  27. }  
  28.   
  29. @Override  
  30. public void computeScroll() {       // update  mScrollX and mScrollY  of View  
  31.     if (mScroller.computeScrollOffset()) {  
  32.         scrollTo(mScroller.getCurrX(), mScroller.getCurrY());  
  33.         postInvalidate();           // invalidate the View from a non-UI thread  
  34.     } else if (mNextPage != INVALID_SCREEN) {  
  35.         mCurrentPage = mNextPage;  
  36.         mNextPage = INVALID_SCREEN;  
  37.         clearChildrenCache();  
  38.     }  
  39. }  
  40.   
  41. @Override  
  42. protected void dispatchDraw(Canvas canvas) {    // draw the child views  
  43.       
  44.     final long drawingTime = getDrawingTime();  // 绘制childView  
  45.     final int count = getChildCount();  
  46.     for (int i = 0; i < count; i++) {  
  47.         drawChild(canvas, getChildAt(i), drawingTime);  
  48.     }  
  49.   
  50.     for (OnScrollListener mListener : mListeners) { // 自定义接口  
  51.         int adjustedScrollX = getScrollX() + pageWidthPadding();  
  52.         mListener.onScroll(adjustedScrollX);  
  53.         if (adjustedScrollX % pageWidth == 0) { // scroll finished  
  54.             mListener.onViewScrollFinished(adjustedScrollX / pageWidth);  
  55.         }  
  56.     }  
  57. }  
  58.   
  59. @Override  
  60. protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  61.     super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  62.   
  63.     pageWidth = (pageWidthSpec == SPEC_UNDEFINED) ? getMeasuredWidth() : pageWidthSpec;  
  64.     pageWidth = Math.min(pageWidth, getMeasuredWidth());  
  65.   
  66.     final int count = getChildCount();  
  67.     for (int i = 0; i < count; i++) {  
  68.         widthMeasureSpec = MeasureSpec.makeMeasureSpec(pageWidth, MeasureSpec.EXACTLY);  
  69.         getChildAt(i).measure(widthMeasureSpec, heightMeasureSpec);  
  70.     }  
  71.   
  72.     if (mFirstLayout) { // 第一次显示Pager时,page的位置  
  73.         scrollTo(getScrollXForPage(mCurrentPage), mScroller.getCurrY());  
  74.         mFirstLayout = false;  
  75.     }  
  76. }  
  77.   
  78. @Override  
  79. protected void onLayout(boolean changed, int left, int top, int right, int bottom) {  
  80.     int childLeft = 0;  
  81.   
  82.     final int count = getChildCount();  // 绘制childView  
  83.     for (int i = 0; i < count; i++) {  
  84.         final View child = getChildAt(i);  
  85.         if (child.getVisibility() != View.GONE) {  
  86.             final int childWidth = child.getMeasuredWidth();  
  87.             child.layout(childLeft, 0, childLeft + childWidth, child.getMeasuredHeight());  
  88.             childLeft += childWidth;  
  89.         }  
  90.     }  
  91. }  

  1. @Override  
  2. public boolean onInterceptTouchEvent(MotionEvent ev) {  
  3.     final int action = ev.getAction();  
  4.     if ((action == MotionEvent.ACTION_MOVE) && (mTouchState != TOUCH_STATE_REST)) { // 正在滑动中  
  5.         return true;  
  6.     }  
  7.   
  8.     final float x = ev.getX();  
  9.     final float y = ev.getY();  
  10.   
  11.     switch (action) {  
  12.     case MotionEvent.ACTION_MOVE:  
  13.         if (mTouchState == TOUCH_STATE_REST) {  
  14.             checkStartScroll(x, y);  
  15.         }  
  16.         break;  
  17.   
  18.     case MotionEvent.ACTION_DOWN:  
  19.         mLastMotionX = x;  
  20.         mLastMotionY = y;  
  21.         mAllowLongPress = true;  
  22.   
  23.         mTouchState = mScroller.isFinished() ? TOUCH_STATE_REST : TOUCH_STATE_SCROLLING;    // scroll 完成后,重置状态  
  24.         break;  
  25.   
  26.     case MotionEvent.ACTION_CANCEL:  
  27.     case MotionEvent.ACTION_UP:  
  28.         clearChildrenCache();  
  29.         mTouchState = TOUCH_STATE_REST;  
  30.         break;  
  31.     }  
  32.   
  33.     return mTouchState != TOUCH_STATE_REST;  
  34. }  
  35.   
  36. @Override  
  37. public boolean onTouchEvent(MotionEvent ev) {  
  38.     if (mVelocityTracker == null) {  
  39.         mVelocityTracker = VelocityTracker.obtain();  
  40.     }  
  41.     mVelocityTracker.addMovement(ev);  
  42.   
  43.     final int action = ev.getAction();  
  44.     final float x = ev.getX();  
  45.     final float y = ev.getY();  
  46.   
  47.     switch (action) {  
  48.     case MotionEvent.ACTION_DOWN:  
  49.         if (!mScroller.isFinished()) {  
  50.             mScroller.abortAnimation();  
  51.         }  
  52.         mLastMotionX = x;  
  53.         break;  
  54.           
  55.     case MotionEvent.ACTION_MOVE:  
  56.         if (mTouchState == TOUCH_STATE_REST) {  
  57.             checkStartScroll(x, y);  
  58.         } else if (mTouchState == TOUCH_STATE_SCROLLING) {  // scrolling 状态时,重绘view  
  59.             int deltaX = (int) (mLastMotionX - x);  
  60.             mLastMotionX = x;  
  61.   
  62.             if (getScrollX() < 0 || getScrollX() > getChildAt(getChildCount() - 1).getLeft()) {  
  63.                 deltaX /= 2;  
  64.             }  
  65.             scrollBy(deltaX, 0);  
  66.         }  
  67.         break;  
  68.           
  69.     case MotionEvent.ACTION_UP:  
  70.         if (mTouchState == TOUCH_STATE_SCROLLING) {  
  71.             final VelocityTracker velocityTracker = mVelocityTracker;  
  72.             velocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);  
  73.             int velocityX = (int) velocityTracker.getXVelocity();  
  74.   
  75.             if (velocityX > SNAP_VELOCITY && mCurrentPage > 0) {  
  76.                 snapToPage(mCurrentPage - 1);  
  77.             } else if (velocityX < -SNAP_VELOCITY && mCurrentPage < getChildCount() - 1) {  
  78.                 snapToPage(mCurrentPage + 1);  
  79.             } else {  
  80.                 snapToDestination();  
  81.             }  
  82.   
  83.             if (mVelocityTracker != null) {  
  84.                 mVelocityTracker.recycle();  
  85.                 mVelocityTracker = null;  
  86.             }  
  87.         }  
  88.         mTouchState = TOUCH_STATE_REST;  
  89.         break;  
  90.     case MotionEvent.ACTION_CANCEL:  
  91.         mTouchState = TOUCH_STATE_REST;  
  92.     }  
  93.   
  94.     return true;  
  95. }  
  96.   
  97. /** 检查scroll状态,并设置绘制scroll缓存 */  
  98. private void checkStartScroll(float x, float y) {  
  99.     final int xDiff = (int) Math.abs(x - mLastMotionX);  
  100.     final int yDiff = (int) Math.abs(y - mLastMotionY);  
  101.   
  102.     boolean xMoved = xDiff > mTouchSlop;  
  103.     boolean yMoved = yDiff > mTouchSlop;  
  104.   
  105.     if (xMoved || yMoved) {  
  106.         if (xMoved) {  
  107.             mTouchState = TOUCH_STATE_SCROLLING;        // 设置为scrolling 状态  
  108.             enableChildrenCache();  
  109.         }  
  110.         if (mAllowLongPress) {  
  111.             mAllowLongPress = false;  
  112.             final View currentScreen = getChildAt(mCurrentPage);  
  113.             currentScreen.cancelLongPress();    // Cancels a pending long press  
  114.         }  
  115.     }  
  116. }  
  117.   
  118. void enableChildrenCache() {  
  119.     setChildrenDrawingCacheEnabled(true);       // Enables or disables the drawing cache for each child of this viewGroup  
  120.     setChildrenDrawnWithCacheEnabled(true); // Tells the ViewGroup to draw its children using their drawing cache  
  121. }  
  122.   
  123. void clearChildrenCache() {  
  124.     setChildrenDrawnWithCacheEnabled(false);  
  125. }  
  126.   
  127. private void snapToDestination() {  
  128.     final int startX = getScrollXForPage(mCurrentPage);  
  129.     int whichPage = mCurrentPage;  
  130.     if (getScrollX() < startX - getWidth() / 8) {  
  131.         whichPage = Math.max(0, whichPage - 1);  
  132.     } else if (getScrollX() > startX + getWidth() / 8) {  
  133.         whichPage = Math.min(getChildCount() - 1, whichPage + 1);  
  134.     }  
  135.   
  136.     snapToPage(whichPage);  
  137. }  
  138.   
  139. void snapToPage(int whichPage) {  
  140.     enableChildrenCache();  
  141.   
  142.     boolean changingPages = whichPage != mCurrentPage;  
  143.   
  144.     mNextPage = whichPage;  
  145.   
  146.     View focusedChild = getFocusedChild();  
  147.     if (focusedChild != null && changingPages && focusedChild == getChildAt(mCurrentPage)) {  
  148.         focusedChild.clearFocus();  
  149.     }  
  150.   
  151.     final int newX = getScrollXForPage(whichPage);  
  152.     final int delta = newX - getScrollX();  
  153.     mScroller.startScroll(getScrollX(), 0, delta, 0, Math.abs(delta) * 2);  
  154.     invalidate();  
  155. }  
  156.   
  157. /** 向左滑动 */  
  158. public void scrollLeft() {  
  159.     if (mNextPage == INVALID_SCREEN && mCurrentPage > 0 && mScroller.isFinished()) {  
  160.         snapToPage(mCurrentPage - 1);  
  161.     }  
  162. }  
  163.   
  164. /** 向右滑动 */  
  165. public void scrollRight() {  
  166.     if (mNextPage == INVALID_SCREEN && mCurrentPage < getChildCount() - 1 && mScroller.isFinished()) {  
  167.         snapToPage(mCurrentPage + 1);  
  168.     }  
  169. }  

C、容器状态保存(onSaveInstanceState)

  1. /** 保存状态 */  
  2. public static class SavedState extends BaseSavedState {  
  3.     int currentScreen = -1;  
  4.   
  5.     SavedState(Parcelable superState) {  
  6.         super(superState);  
  7.     }  
  8.   
  9.     private SavedState(Parcel in) {  
  10.         super(in);  
  11.         currentScreen = in.readInt();  
  12.     }  
  13.   
  14.     public static final Parcelable.Creator<SavedState> CREATOR = new Parcelable.Creator<SavedState>() {  
  15.         public SavedState createFromParcel(Parcel in) { // get data written by Parcelable.writeToParcel()     
  16.             return new SavedState(in);  
  17.         }  
  18.   
  19.         public SavedState[] newArray(int size) {            // create  array of the Parcelable   
  20.             return new SavedState[size];  
  21.         }  
  22.     };  
  23.       
  24.     @Override  
  25.     public void writeToParcel(Parcel out, int flags) {      // set data to parcel  
  26.         super.writeToParcel(out, flags);  
  27.         out.writeInt(currentScreen);  
  28.     }  
  29.   
  30. }  
  31.   
  32. @Override  
  33. protected Parcelable onSaveInstanceState() {        // 保存状态  
  34.     final SavedState state = new SavedState(super.onSaveInstanceState());  
  35.     state.currentScreen = mCurrentPage;     // save InstanceState  
  36.     return state;  
  37. }  
  38.   
  39. @Override  
  40. protected void onRestoreInstanceState(Parcelable state) {   // 恢复状态  
  41.     SavedState savedState = (SavedState) state;  
  42.     super.onRestoreInstanceState(savedState.getSuperState());   // get InstanceState  
  43.     if (savedState.currentScreen != INVALID_SCREEN) {  
  44.         mCurrentPage = savedState.currentScreen;      
  45.     }  
  46. }  

D、容器事件监听接口

  1. public void addOnScrollListener(OnScrollListener listener) {  
  2.     mListeners.add(listener);  
  3. }  
  4.   
  5. public void removeOnScrollListener(OnScrollListener listener) {  
  6.     mListeners.remove(listener);  
  7. }  
  8.   
  9. /** 自定义接口 */  
  10. public static interface OnScrollListener {  
  11.     void onScroll(int scrollX);  
  12.     void onViewScrollFinished(int currentPage);  
  13. }  

代码下载

参考推荐:

Android中自定义属性的使用

Android中自定义属性的格式详解

Scroller(Android)  Scroller(cnblog)

Android Parcelable

Android左右滑动加载分页

抱歉!评论已关闭.