Android 自定义控件---SpreadView

来源:互联网 发布:跑步口罩推荐 知乎 编辑:程序博客网 时间:2024/06/11 11:19

1、效果图主要模仿Fuubo的欢迎界面,一个三层扩散的水波纹.


 

2、实现思路

       

       1、在布局主要用帧布局,让三个水波纹的View重叠

       2、设置三个水波纹的View扩散的延迟时间

       3、可设置三个水波纹的View的坐标,

            可设置是否开始(因为我们有时要Activity中先设置好波纹的坐标,不能让波纹先出现),

            可设置是否为第一次(第一次要进行初始化主要为了设置延迟,不然每次都会有延迟,不同延迟时间的SpreadView相差的时间越来越多)。


3、实现

       根据思路所以接下来要做的一个自定义VIEW就是去绘制一个可扩散的,可设置扩散延迟的实心圆。 


      1、 先设置自定义View属性(attr文件中):

[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <?xml version="1.0" encoding="utf-8"?>  
  2. <resources>  
  3.     <declare-styleable name="SpreadView">  
  4.       <attr name="xDown" format="integer" />  
  5.       <attr name="yDown" format="integer" />  
  6.         <attr name="start" format="boolean" />  
  7.         <attr name="delay" format="integer" />  
  8.         <attr name="first" format="boolean" />  
  9.     </declare-styleable>  
  10.  </resources>  

    2、 然后新建一个继承View的SpreadView类:

[java] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. public class SpreadView extends View {  
  2.   
  3.   
  4.   
  5.     //建立一个波纹的集合    
  6.     private List<Wave> waveList;  
  7.   
  8.       
  9.     //波纹的x,y坐标  
  10.     private int x = 0 ;  
  11.     private int y = 0 ;  
  12.       
  13.       
  14.     //波纹是否在运行,是否为第一次  
  15.     private  boolean start ,first ;  
  16.       
  17.       
  18.     //波纹开始的延迟时间  
  19.     private int delay ;  
  20.   
  21.     public void setStart(boolean start) {  
  22.         this.start = start;  
  23.     }  
  24.   
  25.     public void setFirst(boolean first) {  
  26.         this.first = first;  
  27.     }  
  28.   
  29.   
  30.   
  31.     public void setX(int x) {  
  32.         this.x = x;  
  33.     }  
  34.   
  35.     public void setY(int y) {  
  36.         this.y = y;  
  37.     }  
  38.   
  39.     public void setDelay(int delay) {  
  40.         this.delay = delay;  
  41.     }  
  42.   
  43.   
  44.     //波纹设置的最大透明度  
  45.     private static final int MAX_ALPHA = 255;  
  46.   
  47.   
  48.   
  49.     public SpreadView(Context context, AttributeSet attrs) {  
  50.         super(context, attrs);  
  51.           
  52.         //获取属性信息和设置默认值  
  53.         TypedArray a = context.obtainStyledAttributes(attrs,  
  54.                 R.styleable.SpreadView);  
  55.         x = a.getInt(R.styleable.SpreadView_xDown,0);  
  56.         y = a.getInt(R.styleable.SpreadView_yDown,0);  
  57.         start = a.getBoolean(R.styleable.SpreadView_start,false);  
  58.         delay = a.getInt(R.styleable.SpreadView_delay,0);  
  59.         first = a.getBoolean(R.styleable.SpreadView_first,true);  
  60.   
  61.        //波纹集合的实例化  
  62.         waveList = Collections.synchronizedList(new ArrayList<Wave>());  
  63.   
  64.           
  65.         //记得回收属性容器  
  66.         a.recycle();  
  67.     }  
  68.   
  69.   
  70.   
  71.     @Override  
  72.     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {  
  73.         super.onMeasure(widthMeasureSpec, heightMeasureSpec);  
  74.     }  
  75.       
  76.       
  77.   
  78.     @Override  
  79.     protected void onDraw(Canvas canvas) {  
  80.           
  81.     if(waveList.size()==0&&(!first))  //波纹集合大小为0时,初始化  
  82.       
  83.     init();             //非第一次初始化  
  84.       
  85.     else if(waveList.size()==0&&first)  
  86.           
  87.       initFirst();     //第一次初始化  
  88.     
  89.       
  90.               
  91.             //绘制圆  
  92.             Wave wave = waveList.get(0);  
  93.             if(wave!=null)  
  94.             canvas.drawCircle(wave.xDown, wave.yDown, wave.radius, wave.paint);//用波纹的属性  
  95.   
  96.           
  97.   
  98.     }  
  99.   
  100.       
  101.     private void initFirst() {  
  102.         if(this.start) {             //如果属性值设为开始  
  103.   
  104.             Wave wave = new Wave();  
  105.             wave.radius = 0;  
  106.             wave.alpha = MAX_ALPHA;  
  107.   
  108.             wave.xDown = x;  
  109.             wave.yDown = y;  
  110.             wave.paint = initPaint(wave.alpha);  
  111.   
  112.               
  113.   
  114.   
  115.             waveList.add(wave);  
  116.   
  117.   
  118.               
  119.            first = false;   //设置第一次为false  
  120.            mHandler.sendEmptyMessageDelayed(0, delay);//带延迟异步任务  
  121.   
  122.               
  123.         }  
  124.     }  
  125.   
  126.    //更新画笔  
  127.     private Paint initPaint(int alpha) {  
  128.           
  129.         Paint paint = new Paint();  
  130.   
  131.         paint.setAntiAlias(true);  
  132.       
  133.         paint.setAlpha(alpha);  
  134.       
  135.   
  136.         paint.setColor(Color.WHITE);  
  137.           
  138.         return paint;  
  139.     }  
  140.   
  141.   
  142.     public final Handler.Callback mHandlerCallback = new Handler.Callback(){  
  143.   
  144.   
  145.         @Override  
  146.         public boolean handleMessage(Message msg) {  
  147.   
  148.   
  149.             switch (msg.what){  
  150.   
  151.                 case 0:  
  152.                     refreshState();  
  153.   
  154.                     invalidate();  
  155.   
  156.                     if (waveList != null &&waveList.size()>0) {  
  157.                         mHandler.sendEmptyMessage(0);    //不带延迟的异步  
  158.                     }  
  159.   
  160.                     return true;  
  161.   
  162.                 default:  
  163.                     return false;  
  164.   
  165.             }  
  166.   
  167.   
  168.         }  
  169.     };  
  170.   
  171.     private   Handler mHandler = new Handler(mHandlerCallback);  
  172.   
  173.   
  174.       
  175.     private void refreshState() {  
  176.   
  177.   
  178.             Wave w = waveList.get(0);  
  179.             if (w == null) {  
  180.                 this.postInvalidate();  //如果没有波纹就重新绘制,重新运行onDraw()初始化  
  181.             } else {  
  182.   
  183.                //波纹每次增加的半径大小,可自己修改,记得要转换为px。  
  184.                //(这里0.6单位为dp可以大概指出最大半径),如果不转换,那波纹的最大半径因手机的分辨率不同而不同  
  185.                  
  186.                 w.radius += dip2px(getContext(),0.6f);  
  187.   
  188.                 //波纹每次减小的透明度  
  189.                 w.alpha -= 1;  
  190.   
  191.                //更新波纹的透明度  
  192.                 w.paint.setAlpha(w.alpha);  
  193.                   
  194.                 //当透明度小于0时,清理波纹列表,重新绘制初始化  
  195.                 if (w.alpha < 0) {  
  196.                     waveList.clear();  
  197.                     this.postInvalidate();  
  198.                 }  
  199.   
  200.             }  
  201.   
  202.   
  203.         }  
  204.   
  205.   
  206.   
  207.     public void init() {  
  208.         if(this.start) {  
  209.   
  210.             Wave wave = new Wave();  
  211.             wave.radius = 0;  
  212.             wave.alpha = MAX_ALPHA;  
  213.   
  214.             wave.xDown = x;  
  215.             wave.yDown = y;  
  216.             wave.paint = initPaint(wave.alpha);  
  217.   
  218.   
  219.             waveList.add(wave);  
  220.   
  221.   
  222.               
  223.             mHandler.sendEmptyMessageDelayed(01000);  
  224.   
  225.               
  226.         }  
  227.     }  
  228.   
  229.     private class Wave {  
  230.   
  231.         float radius;  
  232.         Paint paint;  
  233.           
  234.         int xDown;  
  235.           
  236.         int yDown;  
  237.   
  238.         int alpha;  
  239.     }  
  240.   
  241.     public static int dip2px(Context context, float dpValue) {  
  242.         final float scale = context.getResources().getDisplayMetrics().density;  
  243.         return (int) (dpValue * scale + 0.5f);  
  244.     }  
  245. }  
      3、 先设置xml布局:
            注意每个SpreadView的延迟时间和ImageView的属性
[html] view plain copy
print?在CODE上查看代码片派生到我的代码片
  1. <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"  
  2.   
  3.     xmlns:app="http://schemas.android.com/apk/res-auto"  
  4.     android:layout_width="match_parent"  
  5.     android:layout_height="match_parent"  
  6.     android:background="@color/main"  
  7.    >  
  8.   
  9.   
  10.   
  11.     <com.scb.administrator.a.SpreadView  
  12.   
  13.         android:id="@+id/sv"  
  14.         app:xDown="0"  
  15.         app:yDown="0"  
  16.         app:start="false"  
  17.         app:first="true"  
  18.         app:delay="0"  
  19.         android:layout_width="match_parent"  
  20.         android:layout_height="match_parent"  
  21.         />  
  22.   
  23.     <com.scb.administrator.a.SpreadView  
  24.   
  25.         android:id="@+id/sv1"  
  26.         app:xDown="0"  
  27.         app:yDown="0"  
  28.         app:start="false"  
  29.         app:first="true"  
  30.         app:delay="1900"  
  31.         android:layout_width="match_parent"  
  32.         android:layout_height="match_parent"  
  33.         />  
  34.     <com.scb.administrator.a.SpreadView  
  35.   
  36.         android:id="@+id/sv2"  
  37.         app:xDown="0"  
  38.         app:yDown="0"  
  39.         app:first="true"  
  40.         app:start="false"  
  41.         app:delay="3800"  
  42.         android:layout_width="match_parent"  
  43.         android:layout_height="match_parent"  
  44.         />  
  45.   
  46.   
  47.     <RelativeLayout  
  48.         android:layout_width="match_parent"  
  49.         android:layout_height="match_parent"  
  50.         android:background="#00000000"  
  51.         android:id="@+id/re_create2"  
  52.         >  
  53.   
  54.         <TextView  
  55.             android:gravity="center"  
  56.             android:textSize="19sp"  
  57.             android:layout_margin="80dp"  
  58.             android:textStyle="italic"  
  59.             android:textColor="@color/white"  
  60.             android:text="H\nU\nS\nT\nO\nO"  
  61.             android:layout_width="wrap_content"  
  62.             android:layout_height="wrap_content" />  
  63.   
  64.         <ImageView  
  65.             android:id="@+id/go"  
  66.             android:background="#00000000"  
  67.             android:src="@drawable/fap_login"  
  68.             android:layout_margin="40dp"  
  69.             android:scaleType="centerCrop"  
  70.             android:layout_alignParentBottom="true"  
  71.             android:layout_alignParentRight="true"  
  72.             android:layout_width="54dp"  
  73.             android:layout_height="54dp" />  
  74.         </RelativeLayout>  
  75. </FrameLayout>  

         4、接下来我们就要根据上面的布局在Activity手动计算波纹位置了:我们要把波纹的中心设在图片的中心(可看开始的效果图)

[java] view plain copy

 print?在CODE上查看代码片派生到我的代码片
  1. public class SplashActivity extends Activity {  
  2.   
  3.   
  4.   
  5.     private SpreadView sv,sv1,sv2;  
  6.   
  7.     @Override  
  8.     protected void onCreate(Bundle savedInstanceState) {  
  9.         super.onCreate(savedInstanceState);  
  10.         setContentView(R.layout.splash_main);  
  11.   
  12.         sv = (SpreadView) findViewById(R.id.sv);  
  13.         sv1 = (SpreadView) findViewById(R.id.sv1);  
  14.         sv2 = (SpreadView) findViewById(R.id.sv2);  
  15.   
  16.         int statusBarHeight = getStatusHeight(SplashActivity.this);  
  17.   
  18.   
  19.         float scale = getResources().getDisplayMetrics().density;  
  20.   
  21.         DisplayMetrics metrics = new DisplayMetrics();  
  22.         getWindowManager().getDefaultDisplay().getMetrics(metrics);  
  23.         //为什么是67*scale+0.5f?因为从布局文件的ImageView上  
  24.         //上面的式子是一个dp转px的式子,dp为67:ImageView的margin为40+ImageView的半个宽/高  
  25.         int screenWidth= (int) (metrics.widthPixels-(67 * scale + 0.5f));            //屏幕宽度  
  26.         //屏幕高度还要减去状态栏的高度,如果你用的全屏,则不需要了。  
  27.         int screenHeight= (int) (metrics.heightPixels-statusBarHeight-(67 * scale + 0.5f));        //屏幕高度  
  28.   
  29.         ImageView  iv = (ImageView) findViewById(R.id.go);  
  30.   
  31.         sv.setX(screenWidth);  
  32.         sv.setY(screenHeight);  
  33.   
  34.         sv1.setX(screenWidth);  
  35.         sv1.setY(screenHeight);  
  36.   
  37.         sv2.setX(screenWidth);  
  38.         sv2.setY(screenHeight);  
  39.       
  40.         iv.setOnClickListener(new View.OnClickListener() {  
  41.             @Override  
  42.             public void onClick(View v) {  
  43.   
  44.                //TODO  
  45.             }  
  46.         });  
  47.   
  48.   
  49.   
  50.     }  
  51.   
  52.     private int getStatusHeight(Activity activity) {  
  53.         int statusHeight = 0;  
  54.         Rect localRect = new Rect();  
  55.         activity.getWindow().getDecorView().getWindowVisibleDisplayFrame(localRect);  
  56.         statusHeight = localRect.top;  
  57.         if (0 == statusHeight){  
  58.             Class<?> localClass;  
  59.             try {  
  60.                 localClass = Class.forName("com.android.internal.R$dimen");  
  61.                 Object localObject = localClass.newInstance();  
  62.                 int i5 = Integer.parseInt(localClass.getField("status_bar_height").get(localObject).toString());  
  63.                 statusHeight = activity.getResources().getDimensionPixelSize(i5);  
  64.             } catch (ClassNotFoundException e) {  
  65.                 e.printStackTrace();  
  66.             } catch (IllegalAccessException e) {  
  67.                 e.printStackTrace();  
  68.             } catch (InstantiationException e) {  
  69.                 e.printStackTrace();  
  70.             } catch (NumberFormatException e) {  
  71.                 e.printStackTrace();  
  72.             } catch (IllegalArgumentException e) {  
  73.                 e.printStackTrace();  
  74.             } catch (SecurityException e) {  
  75.                 e.printStackTrace();  
  76.             } catch (NoSuchFieldException e) {  
  77.                 e.printStackTrace();  
  78.             }  
  79.         }  
  80.         return statusHeight;  
  81.     }  
  82.   
  83.     @Override  
  84.     protected void onResume() {  
  85.         //根据Activity的生命周期来设置  
  86.         sv1.setStart(false);  
  87.         sv.setStart(false);  
  88.         sv2.setStart(false);  
  89.         sv1.setStart(true);  
  90.         sv.setStart(true);  
  91.         sv2.setStart(true);  
  92.         sv1.setFirst(true);  
  93.         sv.setFirst(true);  
  94.         sv2.setFirst(true);  
  95.         super.onResume();  
  96.     }  
  97.   
  98.     @Override  
  99.     protected void onPause() {  
  100.   
  101.         super.onPause();  
  102.     }  
  103.   
  104.   
  105. }  



  
    转载请注明出处:http://blog.csdn.net/cxmscb/article/details/48441583

0 0
原创粉丝点击