仿Twitter登陆移动背景效果
有使用Twitter客户端的朋友应该有发现在登录的时候,屏幕上方和下方的云朵图片是不断移动着的,再加上Twitter那支可爱的小鸟在不停的动着,给人的感觉就好像是小鸟在飞翔一样,感觉效果很不错。
我也试着实现了一下,发现使用自定义的Drawable加上线程,还是比较容易实现的。下面是自定义Drawable的代码,注释已经写的很详细了。这里是使用了三张图片,使用一张图就更简单了,大家完全可以举一反三,实现自己的动画图片效果。
package com.liuzhichao.dynamicdrawable; import android.app.Activity; import android.graphics.Bitmap; import android.graphics.BitmapFactory; import android.graphics.Canvas; import android.graphics.ColorFilter; import android.graphics.drawable.Drawable; import android.util.DisplayMetrics; import android.view.View; public class DynamicDrawable extends Drawable implements Runnable { private static Bitmap mBottomBgBitmap; //底部大图 private static Bitmap mBottomFgBitmap; // 底部小图 private static Bitmap mTopBitmap; //顶部云图片 private final int dispalyWidth; //手机屏幕宽度 private final int dispalyHeight; //手机屏幕高度 private float mBottomBgTop; //顶部大图显示的位置 private float mBottomFgTop; //顶部小图显示的位置 private int startX; //顶部云图片和底部大图移动偏移变量 private int mBottomFgStartX; //底部小图移动偏移变量 private View mView; public DynamicDrawable(Activity activity, View mView) { this.mView = mView; if (mTopBitmap == null) { mTopBitmap = BitmapFactory.decodeResource(activity.getResources(), R.drawable.cloud_top_bg); } if (mBottomBgBitmap == null) { mBottomBgBitmap = BitmapFactory.decodeResource( activity.getResources(), R.drawable.cloud_bottom_bg); } if (mBottomFgBitmap == null) { mBottomFgBitmap = BitmapFactory.decodeResource( activity.getResources(), R.drawable.cloud_bottom_fg); } //获取屏幕高度和宽度 DisplayMetrics dm = new DisplayMetrics(); dm = activity.getResources().getDisplayMetrics(); this.dispalyHeight = dm.heightPixels; this.dispalyWidth = dm.widthPixels; //顶部图片显示的位置 = 屏幕高度 - 图片自身高 - 标题高度 this.mBottomBgTop = dispalyHeight - mBottomBgBitmap.getHeight() - 100; this.mBottomFgTop = dispalyHeight - mBottomFgBitmap.getHeight() - 100; //开始移动图片线程 new Thread(this).start(); } @Override public void draw(Canvas canvas) { // drawBitmap (Bitmap bitmap, float left, float top, Paint paint) canvas.drawBitmap(mTopBitmap, startX, 0, null); canvas.drawBitmap(mBottomBgBitmap, startX, mBottomBgTop, null); canvas.drawBitmap(mBottomFgBitmap, mBottomFgStartX, mBottomFgTop, null); } @Override public int getOpacity() { // TODO Auto-generated method stub return 0; } @Override public void setAlpha(int arg0) { // TODO Auto-generated method stub } @Override public void setColorFilter(ColorFilter arg0) { // TODO Auto-generated method stub } @Override public void run() { while (!Thread.currentThread().isInterrupted()) { //900 是图片的长度 //如果移动偏量已经大于图片的长度 - 屏幕宽度,则说明已经移动到了图片的末端,如果继续移动,则会显示空白 //所以将startX重新赋予0,让图片重新开始移动 //但是这样过渡效果会比较明显,再切换的那一刹那,会明显感觉图片变化较大 if (startX + (900 - dispalyWidth) == 0) { startX = 0; } else { startX -= 1; } //底部小图的移动, // -=2 是让小图移动的比大图快,造成不同的视觉效果 if (mBottomFgStartX + (900 - dispalyWidth) == 0) { mBottomFgStartX = 0; } else { mBottomFgStartX -= 2; } try { //每 1/10秒移动一次 Thread.sleep(100L); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } //刷新界面 mView.postInvalidate(); } } }
然后在需要背景图的地方,直接setBackgroundDrawable就可以了,下面的background是整个布局文件的id。
private View background; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); background = findViewById(android.R.id.background); background.setBackgroundDrawable(new DynamicDrawable(this, background)); }
布局文件也还是贴出来吧:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:id="@android:id/background" > <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:padding="@dimen/padding_medium" android:text="@string/hello_world" tools:context=".MainActivity" /> </RelativeLayout>
还是截张图吧,虽然看不到动画效果。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
2013-04-23 android 获取当前系统及应用信息(二)