今天记录一下TextView的倒影效果,显示一串文字,然后在文字的下方显示出它的倒影,先上效果图:
最重要的就是View中getDrawingCache()方法,该方法可以获取cache中的图像,然后绘制出来。
废话不多说,我是想写一个带有倒影的时间,时间可以走动。首先先写一个带有时间走动的View,这个很简单,获取当前时间,然后开启一个线程,隔一秒获取当前时间一次,然后显示在TextView上,当然,我们写控件,就需要继承TextView,代码如下:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">package</span><span style="color: #000000;"> com.alex.reflecttextview;</p><p></span><span style="color: #008080;"> 2</span> </p><p><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> java.util.Calendar;</p><p></span><span style="color: #008080;"> 4</span> </p><p><span style="color: #008080;"> 5</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.content.Context;</p><p></span><span style="color: #008080;"> 6</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.os.Handler;</p><p></span><span style="color: #008080;"> 7</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.os.Message;</p><p></span><span style="color: #008080;"> 8</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.text.format.DateFormat;</p><p></span><span style="color: #008080;"> 9</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.util.AttributeSet;</p><p></span><span style="color: #008080;">10</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.widget.TextView;</p><p></span><span style="color: #008080;">11</span> </p><p><span style="color: #008080;">12</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> TimeView <span style="color: #0000ff;">extends</span><span style="color: #000000;"> TextView {</p><p></span><span style="color: #008080;">13</span> </p><p><span style="color: #008080;">14</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">static</span> <span style="color: #0000ff;">final</span> <span style="color: #0000ff;">int</span> MESSAGE_TIME = 1<span style="color: #000000;">;</p><p></span><span style="color: #008080;">15</span> </p><p><span style="color: #008080;">16</span> <span style="color: #0000ff;">public</span><span style="color: #000000;"> TimeView(Context context, AttributeSet attrs) {</p><p></span><span style="color: #008080;">17</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">(context, attrs);</p><p></span><span style="color: #008080;">18</span> <span style="color: #0000ff;">new</span><span style="color: #000000;"> TimeThread().start();</p><p></span><span style="color: #008080;">19</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">20</span> </p><p><span style="color: #008080;">21</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> TimeThread <span style="color: #0000ff;">extends</span><span style="color: #000000;"> Thread {</p><p></span><span style="color: #008080;">22</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">23</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> run() {</p><p></span><span style="color: #008080;">24</span> <span style="color: #0000ff;">do</span><span style="color: #000000;"> {</p><p></span><span style="color: #008080;">25</span> <span style="color: #0000ff;">try</span><span style="color: #000000;"> {</p><p></span><span style="color: #008080;">26</span> Message msg = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Message();</p><p></span><span style="color: #008080;">27</span> msg.what =<span style="color: #000000;"> MESSAGE_TIME;</p><p></span><span style="color: #008080;">28</span> <span style="color: #000000;"> mHandler.sendMessage(msg);</p><p></span><span style="color: #008080;">29</span> Thread.sleep(1000<span style="color: #000000;">);</p><p></span><span style="color: #008080;">30</span> } <span style="color: #0000ff;">catch</span><span style="color: #000000;"> (InterruptedException e) {</p><p></span><span style="color: #008080;">31</span> <span style="color: #000000;"> e.printStackTrace();</p><p></span><span style="color: #008080;">32</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">33</span> } <span style="color: #0000ff;">while</span> (<span style="color: #0000ff;">true</span><span style="color: #000000;">);</p><p></span><span style="color: #008080;">34</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">35</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">36</span> </p><p><span style="color: #008080;">37</span> <span style="color: #0000ff;">private</span> Handler mHandler = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Handler() {</p><p></span><span style="color: #008080;">38</span> </p><p><span style="color: #008080;">39</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">40</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> handleMessage(Message msg) {</p><p></span><span style="color: #008080;">41</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.handleMessage(msg);</p><p></span><span style="color: #008080;">42</span> <span style="color: #0000ff;">switch</span><span style="color: #000000;"> (msg.what) {</p><p></span><span style="color: #008080;">43</span> <span style="color: #0000ff;">case</span><span style="color: #000000;"> MESSAGE_TIME:</p><p></span><span style="color: #008080;">44</span> <span style="color: #000000;"> setTime();</p><p></span><span style="color: #008080;">45</span> <span style="color: #0000ff;">break</span><span style="color: #000000;">;</p><p></span><span style="color: #008080;">46</span> </p><p><span style="color: #008080;">47</span> <span style="color: #0000ff;">default</span><span style="color: #000000;">:</p><p></span><span style="color: #008080;">48</span> <span style="color: #0000ff;">break</span><span style="color: #000000;">;</p><p></span><span style="color: #008080;">49</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">50</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">51</span> <span style="color: #000000;"> };</p><p></span><span style="color: #008080;">52</span> </p><p><span style="color: #008080;">53</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> setTime() {</p><p></span><span style="color: #008080;">54</span> <span style="color: #0000ff;">long</span> sysTime =<span style="color: #000000;"> System.currentTimeMillis();</p><p></span><span style="color: #008080;">55</span> Calendar calendar =<span style="color: #000000;"> Calendar.getInstance();</p><p></span><span style="color: #008080;">56</span> <span style="color: #000000;"> calendar.setTimeInMillis(sysTime);</p><p></span><span style="color: #008080;">57</span> String sysTimeStr = DateFormat.format("hh:mm"<span style="color: #000000;">, sysTime).toString();</p><p></span><span style="color: #008080;">58</span> <span style="color: #0000ff;">if</span>(calendar.get(Calendar.AM_PM) == 0<span style="color: #000000;">) {</p><p></span><span style="color: #008080;">59</span> sysTimeStr += " AM"<span style="color: #000000;">;</p><p></span><span style="color: #008080;">60</span> } <span style="color: #0000ff;">else</span><span style="color: #000000;"> {</p><p></span><span style="color: #008080;">61</span> sysTimeStr += " PM"<span style="color: #000000;">;</p><p></span><span style="color: #008080;">62</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">63</span> setText(sysTimeStr.replace("1", " 1"<span style="color: #000000;">));</p><p></span><span style="color: #008080;">64</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">65</span> }
现在只需要在布局文件中调用该控件就可以实现一个走动的时间了。
第二步就是需要给这个走动的时间加上倒影了,我们就需要写一个控件来继承上面一个时间走动的控件,就可以实现带有倒影的时间走动的View了,下面是带有倒影的代码:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">package</span><span style="color: #000000;"> com.alex.reflecttextview;</p><p></span><span style="color: #008080;"> 2</span> </p><p><span style="color: #008080;"> 3</span> </p><p><span style="color: #008080;"> 4</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.content.Context;</p><p></span><span style="color: #008080;"> 5</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Bitmap;</p><p></span><span style="color: #008080;"> 6</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Canvas;</p><p></span><span style="color: #008080;"> 7</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.LinearGradient;</p><p></span><span style="color: #008080;"> 8</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Matrix;</p><p></span><span style="color: #008080;"> 9</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Paint;</p><p></span><span style="color: #008080;">10</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.PorterDuff.Mode;</p><p></span><span style="color: #008080;">11</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.PorterDuffXfermode;</p><p></span><span style="color: #008080;">12</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Shader.TileMode;</p><p></span><span style="color: #008080;">13</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.util.AttributeSet;</p><p></span><span style="color: #008080;">14</span> </p><p><span style="color: #008080;">15</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> ReflectTextView <span style="color: #0000ff;">extends</span><span style="color: #000000;"> TimeView {</p><p></span><span style="color: #008080;">16</span> </p><p><span style="color: #008080;">17</span> <span style="color: #0000ff;">private</span><span style="color: #000000;"> Matrix mMatrix;</p><p></span><span style="color: #008080;">18</span> <span style="color: #0000ff;">private</span><span style="color: #000000;"> Paint mPaint;</p><p></span><span style="color: #008080;">19</span> </p><p><span style="color: #008080;">20</span> <span style="color: #0000ff;">public</span><span style="color: #000000;"> ReflectTextView(Context context, AttributeSet attrs) {</p><p></span><span style="color: #008080;">21</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">(context, attrs);</p><p></span><span style="color: #008080;">22</span> <span style="color: #000000;"> init();</p><p></span><span style="color: #008080;">23</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">24</span> </p><p><span style="color: #008080;">25</span> <span style="color: #0000ff;">private</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> init() {</p><p></span><span style="color: #008080;">26</span> mMatrix = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Matrix();</p><p></span><span style="color: #008080;">27</span> mMatrix.preScale(1, -1<span style="color: #000000;">);</p><p></span><span style="color: #008080;">28</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">29</span> </p><p><span style="color: #008080;">30</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">31</span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span> onMeasure(<span style="color: #0000ff;">int</span> widthMeasureSpec, <span style="color: #0000ff;">int</span><span style="color: #000000;"> heightMeasureSpec) {</p><p></span><span style="color: #008080;">32</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.onMeasure(widthMeasureSpec, heightMeasureSpec);</p><p></span><span style="color: #008080;">33</span> setMeasuredDimension(getMeasuredWidth(), (<span style="color: #0000ff;">int</span>)(getMeasuredHeight()*1.67<span style="color: #000000;">));</p><p></span><span style="color: #008080;">34</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">35</span> </p><p><span style="color: #008080;">36</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">37</span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onDraw(Canvas canvas) {</p><p></span><span style="color: #008080;">38</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.onDraw(canvas);</p><p></span><span style="color: #008080;">39</span> <span style="color: #0000ff;">int</span> height =<span style="color: #000000;"> getHeight();</p><p></span><span style="color: #008080;">40</span> <span style="color: #0000ff;">int</span> width =<span style="color: #000000;"> getWidth();</p><p></span><span style="color: #008080;">41</span> setDrawingCacheEnabled(<span style="color: #0000ff;">true</span><span style="color: #000000;">);</p><p></span><span style="color: #008080;">42</span> Bitmap originalImage =<span style="color: #000000;"> Bitmap.createBitmap(getDrawingCache());</p><p></span><span style="color: #008080;">43</span> Bitmap reflectionImage = Bitmap.createBitmap(originalImage, 0, height/5, width, height/2, mMatrix, <span style="color: #0000ff;">false</span><span style="color: #000000;">);</p><p></span><span style="color: #008080;">44</span> canvas.drawBitmap(reflectionImage, 0, height/3f, <span style="color: #0000ff;">null</span><span style="color: #000000;">);</p><p></span><span style="color: #008080;">45</span> <span style="color: #0000ff;">if</span>(mPaint == <span style="color: #0000ff;">null</span><span style="color: #000000;">) {</p><p></span><span style="color: #008080;">46</span> mPaint = <span style="color: #0000ff;">new</span><span style="color: #000000;"> Paint(); </p><p></span><span style="color: #008080;">47</span> LinearGradient shader = <span style="color: #0000ff;">new</span> LinearGradient(0, height/2, 0<span style="color: #000000;">,</p><p></span><span style="color: #008080;">48</span> height, 0x7fffffff, 0x0fffffff<span style="color: #000000;">, TileMode.CLAMP);</p><p></span><span style="color: #008080;">49</span> <span style="color: #000000;"> mPaint.setShader(shader);</p><p></span><span style="color: #008080;">50</span> mPaint.setXfermode(<span style="color: #0000ff;">new</span><span style="color: #000000;"> PorterDuffXfermode(Mode.DST_IN)); </p><p></span><span style="color: #008080;">51</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">52</span> canvas.drawRect(0, height/<span style="color: #000000;">2f, width, height, mPaint);</p><p></span><span style="color: #008080;">53</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">54</span> </p><p><span style="color: #008080;">55</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">56</span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span> onTextChanged(CharSequence text, <span style="color: #0000ff;">int</span><span style="color: #000000;"> start,</p><p></span><span style="color: #008080;">57</span> <span style="color: #0000ff;">int</span> lengthBefore, <span style="color: #0000ff;">int</span><span style="color: #000000;"> lengthAfter) {</p><p></span><span style="color: #008080;">58</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.onTextChanged(text, start, lengthBefore, lengthAfter);</p><p></span><span style="color: #008080;">59</span> <span style="color: #000000;"> buildDrawingCache();</p><p></span><span style="color: #008080;">60</span> <span style="color: #000000;"> postInvalidate();</p><p></span><span style="color: #008080;">61</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">62</span> }
主要功能在onDraw方法里面,先调用setDrawingCacheEnabled(true);让cache可用,然后通过cache创建一个和原图片一样的图像,通过mMatrix.preScale(1, -1);使图片倒过来,调用Bitmap.createBitmap(originalImage, 0, height/5, width, height/2, mMatrix, false);创建一个倒过来的图像,调用canvas.drawBitmap(reflectionImage, 0, height/3f, null);把倒过来的图像画到画布上。通过调用LinearGradient shader = new LinearGradient(0, height/2, 0,
height, 0x7fffffff, 0x0fffffff, TileMode.CLAMP);
mPaint.setShader(shader);
mPaint.setXfermode(new PorterDuffXfermode(Mode.DST_IN));使倒影的图像的颜色渐变,由灰色变为黑色。
时间走动时调用buildDrawingCache();
postInvalidate();
让倒影从新绘制。
调用setMeasuredDimension(getMeasuredWidth(), (int)(getMeasuredHeight()*1.67));设置图像的宽度和高度。
好了,控件已经写完了,现在只要在布局中调用这个控件就可以在Activity中显示一个带有倒影的时间的View了,先写一个布局文件:
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;"><?</span><span style="color: #ff00ff;">xml version="1.0" encoding="utf-8"</span><span style="color: #0000ff;">?></span></p><p><span style="color: #008080;"> 2</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">RelativeLayout </span><span style="color: #ff0000;">xmlns:android</span><span style="color: #0000ff;">="http://schemas.android.com/apk/res/android"</span></p><p><span style="color: #008080;"> 3</span> <span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="match_parent"</span></p><p><span style="color: #008080;"> 4</span> <span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="match_parent"</span></p><p><span style="color: #008080;"> 5</span> <span style="color: #ff0000;"> android:background</span><span style="color: #0000ff;">="#000000"</span></p><p><span style="color: #008080;"> 6</span> <span style="color: #ff0000;"> android:paddingTop</span><span style="color: #0000ff;">="@dimen/activity_vertical_margin"</span> <span style="color: #0000ff;">></span></p><p><span style="color: #008080;"> 7</span> </p><p><span style="color: #008080;"> 8</span> <span style="color: #0000ff;"><</span><span style="color: #800000;">com.alex.reflecttextview.ReflectTextView</p><p></span><span style="color: #008080;"> 9</span> <span style="color: #ff0000;">android:id</span><span style="color: #0000ff;">="@+id/timeView"</span></p><p><span style="color: #008080;">10</span> <span style="color: #ff0000;"> android:textSize</span><span style="color: #0000ff;">="@dimen/reflect_size"</span></p><p><span style="color: #008080;">11</span> <span style="color: #ff0000;"> android:layout_width</span><span style="color: #0000ff;">="match_parent"</span></p><p><span style="color: #008080;">12</span> <span style="color: #ff0000;"> android:layout_height</span><span style="color: #0000ff;">="wrap_content"</span></p><p><span style="color: #008080;">13</span> <span style="color: #ff0000;"> android:layout_alignParentBottom</span><span style="color: #0000ff;">="true"</span></p><p><span style="color: #008080;">14</span> <span style="color: #ff0000;"> android:gravity</span><span style="color: #0000ff;">="top|center_horizontal"</span> <span style="color: #0000ff;">/></span></p><p><span style="color: #008080;">15</span> <span style="color: #0000ff;"></</span><span style="color: #800000;">RelativeLayout</span><span style="color: #0000ff;">></span>
然后在Activity中显示这个布局,我把这个控件的字体从新设置了一下,让它显示的方方正正。
<span style="color: #008080;"> 1</span> <span style="color: #0000ff;">package</span><span style="color: #000000;"> com.alex.reflecttextview;</p><p></span><span style="color: #008080;"> 2</span> </p><p><span style="color: #008080;"> 3</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.app.Activity;</p><p></span><span style="color: #008080;"> 4</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.graphics.Typeface;</p><p></span><span style="color: #008080;"> 5</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.os.Bundle;</p><p></span><span style="color: #008080;"> 6</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.view.Window;</p><p></span><span style="color: #008080;"> 7</span> <span style="color: #0000ff;">import</span><span style="color: #000000;"> android.view.WindowManager;</p><p></span><span style="color: #008080;"> 8</span> </p><p><span style="color: #008080;"> 9</span> <span style="color: #0000ff;">public</span> <span style="color: #0000ff;">class</span> MainActivity <span style="color: #0000ff;">extends</span><span style="color: #000000;"> Activity {</p><p></span><span style="color: #008080;">10</span> </p><p><span style="color: #008080;">11</span> <span style="color: #000000;"> @Override</p><p></span><span style="color: #008080;">12</span> <span style="color: #0000ff;">protected</span> <span style="color: #0000ff;">void</span><span style="color: #000000;"> onCreate(Bundle savedInstanceState) {</p><p></span><span style="color: #008080;">13</span> <span style="color: #0000ff;">super</span><span style="color: #000000;">.onCreate(savedInstanceState);</p><p></span><span style="color: #008080;">14</span> <span style="color: #0000ff;">final</span> Window win =<span style="color: #000000;"> getWindow();</p><p></span><span style="color: #008080;">15</span> <span style="color: #000000;"> win.addFlags(WindowManager.LayoutParams.FLAG_SHOW_WHEN_LOCKED</p><p></span><span style="color: #008080;">16</span> |<span style="color: #000000;"> WindowManager.LayoutParams.FLAG_DISMISS_KEYGUARD);</p><p></span><span style="color: #008080;">17</span> <span style="color: #000000;"> win.addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON</p><p></span><span style="color: #008080;">18</span> |<span style="color: #000000;"> WindowManager.LayoutParams.FLAG_TURN_SCREEN_ON);</p><p></span><span style="color: #008080;">19</span> <span style="color: #000000;"> setContentView(R.layout.activity_main);</p><p></span><span style="color: #008080;">20</span> TimeView tv =<span style="color: #000000;"> (TimeView) findViewById(R.id.timeView);</p><p></span><span style="color: #008080;">21</span> tv.setTypeface(Typeface.createFromAsset(getAssets(), "fonts/DS-DIGII.TTF"<span style="color: #000000;">));</p><p></span><span style="color: #008080;">22</span> <span style="color: #000000;"> }</p><p></span><span style="color: #008080;">23</span> }
运行代码,手机上就回显示一个带有倒影的时间View,时间还会走动,是不是很好玩。
好了,就到这里吧。
源代码下载请点我。