源码已经上传至我的github上:github.com/junmei520/M…
好了,带闪烁效果的礼物下落也实现了。
其实跑马灯效果的实现也可以不用自定义TextView,只要在代码中在进行相关设置就可以了。但是我个人比较喜欢用自定义。
同时我在微博上也以视频的形式展示了Demo的运行效果:weibo.com/u/532359340…
圣诞将至,闲来无事,于是,便做了一个圣诞祝福小Demo,也祝大家圣诞快乐,每天开心~
由于灵感来的比较迟,所以demo做的很简陋,还请见谅。但我觉得,我的想法还是很好的~
运行效果图:
Demo特点描述:
①一打开Demo便有背景音乐响起。
②具有带闪烁变换的礼物下落效果。
③跑马灯显示滚动文本。
Demo设计的知识点:
① 使用Service开启背景音乐Jingle Bells。
②自定义View实现礼物闪烁变换的下落。
③自定义TextView实现跑马灯效果展示文本。
具体实现如下(由于代码都十分简单,这里我只做简略说明):
一、使用Service开启背景音乐Jingle Bells:
先写一个音乐播放的服务类:
- public class MusicService extends Service {
- @Override
- public IBinder onBind(Intent intent) {
- return null;
- }
- MediaPlayer player;
- @Override
- public int onStartCommand(Intent intent, int flags, int startId) {
- String action = intent.getStringExtra("action");
- if ("play".equals(action)) {
- //播放
- play();
- } else if ("stop".equals(action)) {
- //停止
- stop();
- }
- return super.onStartCommand(intent, flags, startId);
- }
- private void stop() {
- if (player != null) {
- player.stop();
- player.reset();
- player.release();//释放加载的文件
- player = null;//不要忘了!
- }
- }
- private void play() {
- if (player == null) {
- player = MediaPlayer.create(this, R.raw.jinglebells);
- player.setLooping(true);
- }
- if (player != null && !player.isPlaying()) {
- player.start();
- }
- }
- @Override
- public void onDestroy() {
- super.onDestroy();
- stop();//停止音乐
- }
public class MusicService extends Service {
@Override
public IBinder onBind(Intent intent) {
return null;
}
MediaPlayer player;
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
String action = intent.getStringExtra("action");
if ("play".equals(action)) {
//播放
play();
} else if ("stop".equals(action)) {
//停止
stop();
}
return super.onStartCommand(intent, flags, startId);
}
private void stop() {
if (player != null) {
player.stop();
player.reset();
player.release();//释放加载的文件
player = null;//不要忘了!
}
}
private void play() {
if (player == null) {
player = MediaPlayer.create(this, R.raw.jinglebells);
player.setLooping(true);
}
if (player != null && !player.isPlaying()) {
player.start();
}
}
@Override
public void onDestroy() {
super.onDestroy();
stop();//停止音乐
}
音乐文件放在raw中:
在功能清单文件中进行注册:
<!--功能清单文件中注册服务-->
<service android:name=".service.MusicService" />
在MainAcitivity中启动、停止服务:
- public class MainActivity extends AppCompatActivity {
- private Intent intent;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //应用一进入就开启服务,启动音乐播放
- intent = new Intent(this, MusicService.class);
- intent.putExtra("action", "play");
- startService(intent);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //此处我们简洁化,当activity退出时就直接停止音乐的播放
- intent.putExtra("action", "stop");
- startService(intent);
- stopService(intent);
- }
- }
public class MainActivity extends AppCompatActivity {
private Intent intent;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//应用一进入就开启服务,启动音乐播放
intent = new Intent(this, MusicService.class);
intent.putExtra("action", "play");
startService(intent);
}
@Override
protected void onDestroy() {
super.onDestroy();
//此处我们简洁化,当activity退出时就直接停止音乐的播放
intent.putExtra("action", "stop");
startService(intent);
stopService(intent);
}
}
至此,背景音乐的播放完成了。
二、自定义View实现礼物闪烁变换的下落
自定义GiftView继承View:
- /**
- * 自定义礼物散落的view
- */
- public class GiftView extends View{
- public GiftView(Context context) {
- this(context,null);
- }
- public GiftView(Context context, AttributeSet attrs) {
- this(context, attrs,0);
- }
- public GiftView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
- private static final Random random = new Random();
- //准备礼物的图片数组
- private int[] drawables={R.drawable.p0,R.drawable.p1,R.drawable.p2,R.drawable.p3,R.drawable.p5,
- R.drawable.p6,R.drawable.p7,R.drawable.p8,R.drawable.p9,R.drawable.p10};
- // 用于画礼物的画笔
- private final Paint myPaint = new Paint();
- //坐标类的数组---礼物的位置
- private Coordinate[] gifts = new Coordinate[80];
- //窗体的初始高宽
- int sHeight = 0;
- int sWidth = 0;
- //记录礼物的个数
- private int giftCount = 0;
- /**
- * 设置当前窗体的实际宽高
- */
- public void SetView(int height, int width) {
- sHeight = height - 100;
- sWidth = width;
- }
- /**
- * 随机的产生礼物的位置
- */
- public void produceGiftRandom(int count) {
- giftCount = count;
- for (int i = 0; i < count; i++) {
- //横坐标和纵坐标都是随机产生的
- gifts[i] = new Coordinate(random.nextInt(sWidth), -random.nextInt(sHeight));
- }
- }
- /**
- * 通过画笔将礼物绘制上去
- */
- @Override
- public void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- for (int x = 0; x < giftCount; x += 1) {
- if (gifts[x].mY >= sHeight) {
- gifts[x].mY = 0;
- }
- // 礼物下落的数值速度
- gifts[x].mY += 10;
- // 让礼物飘动起来
- if (random.nextBoolean()) {
- //让水平方向有一个随机移动的速度
- int ran = random.nextInt(12);
- gifts[x].mX += 2 - ran;
- if(gifts[x].mX < 0){
- gifts[x].mX = sWidth;
- }else if(gifts[x].mX > sWidth){
- gifts[x].mX = 0;
- }
- }
- Resources mResources = getResources();
- int drawableIndex=random.nextInt(10);
- //不断的切换十张图片造成闪烁的效果
- canvas.drawBitmap(((BitmapDrawable) mResources.getDrawable(drawables[drawableIndex])).getBitmap(), ((float) gifts[x].mX),
- ((float) gifts[x].mY), myPaint);
- }
- }
- /**
- * 自定义一个坐标类
- */
- private class Coordinate{
- public int mX;
- public int mY;
- public Coordinate(int x, int y) {
- mX = x;
- mY = y;
- }
- }
- }
/**
* 自定义礼物散落的view
*/
public class GiftView extends View{
public GiftView(Context context) {
this(context,null);
}
public GiftView(Context context, AttributeSet attrs) {
this(context, attrs,0);
}
public GiftView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
private static final Random random = new Random();
//准备礼物的图片数组
private int[] drawables={R.drawable.p0,R.drawable.p1,R.drawable.p2,R.drawable.p3,R.drawable.p5,
R.drawable.p6,R.drawable.p7,R.drawable.p8,R.drawable.p9,R.drawable.p10};
// 用于画礼物的画笔
private final Paint myPaint = new Paint();
//坐标类的数组---礼物的位置
private Coordinate[] gifts = new Coordinate[80];
//窗体的初始高宽
int sHeight = 0;
int sWidth = 0;
//记录礼物的个数
private int giftCount = 0;
/**
* 设置当前窗体的实际宽高
*/
public void SetView(int height, int width) {
sHeight = height - 100;
sWidth = width;
}
/**
* 随机的产生礼物的位置
*/
public void produceGiftRandom(int count) {
giftCount = count;
for (int i = 0; i < count; i++) {
//横坐标和纵坐标都是随机产生的
gifts[i] = new Coordinate(random.nextInt(sWidth), -random.nextInt(sHeight));
}
}
/**
* 通过画笔将礼物绘制上去
*/
@Override
public void onDraw(Canvas canvas) {
super.onDraw(canvas);
for (int x = 0; x < giftCount; x += 1) {
if (gifts[x].mY >= sHeight) {
gifts[x].mY = 0;
}
// 礼物下落的数值速度
gifts[x].mY += 10;
// 让礼物飘动起来
if (random.nextBoolean()) {
//让水平方向有一个随机移动的速度
int ran = random.nextInt(12);
gifts[x].mX += 2 - ran;
if(gifts[x].mX < 0){
gifts[x].mX = sWidth;
}else if(gifts[x].mX > sWidth){
gifts[x].mX = 0;
}
}
Resources mResources = getResources();
int drawableIndex=random.nextInt(10);
//不断的切换十张图片造成闪烁的效果
canvas.drawBitmap(((BitmapDrawable) mResources.getDrawable(drawables[drawableIndex])).getBitmap(), ((float) gifts[x].mX),
((float) gifts[x].mY), myPaint);
}
}
/**
* 自定义一个坐标类
*/
private class Coordinate{
public int mX;
public int mY;
public Coordinate(int x, int y) {
mX = x;
mY = y;
}
}
}
在布局中使用自定义View:
- <!--在布局中使用自定义View-->
- <com.chrismas.shiyu.mychristmas.view.GiftView
- android:id="@+id/gift"
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
<!--在布局中使用自定义View-->
<com.chrismas.shiyu.mychristmas.view.GiftView
android:id="@+id/gift"
android:layout_width="match_parent"
android:layout_height="match_parent" />
在MainActivity中进行相关操作:
- public class MainActivity extends AppCompatActivity {
- private Intent intent;
- //礼物总个数
- private int GIFTCOUNT = 30;
- GiftView giftView = null;
- //使用handler进行消息的处理,不断进行重绘
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == 1) {
- //重绘
- giftView.invalidate();
- mHandler.sendEmptyMessageDelayed(1, 100);
- }
- }
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //应用一进入就开启服务,启动音乐播放
- intent = new Intent(this, MusicService.class);
- intent.putExtra("action", "play");
- startService(intent);
- //产生礼物洒落效果
- giftView = (GiftView) findViewById(R.id.gift);
- // 获取当前屏幕的高宽
- DisplayMetrics dm = new DisplayMetrics();
- getWindowManager().getDefaultDisplay().getMetrics(dm);
- giftView.SetView(dm.heightPixels, dm.widthPixels);
- // 不断更新礼物
- update();
- }
- public void update() {
- giftView.produceGiftRandom(GIFTCOUNT);
- //发送延迟消息
- mHandler.sendEmptyMessageDelayed(1, 100);
- }
- @Override
- protected void onDestroy() {
- super.onDestroy();
- //此处我们简洁化,当activity退出时就直接停止音乐的播放
- intent.putExtra("action", "stop");
- startService(intent);
- stopService(intent);
- }
- }
public class MainActivity extends AppCompatActivity {
private Intent intent;
//礼物总个数
private int GIFTCOUNT = 30;
GiftView giftView = null;
//使用handler进行消息的处理,不断进行重绘
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
if (msg.what == 1) {
//重绘
giftView.invalidate();
mHandler.sendEmptyMessageDelayed(1, 100);
}
}
};
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//应用一进入就开启服务,启动音乐播放
intent = new Intent(this, MusicService.class);
intent.putExtra("action", "play");
startService(intent);
//产生礼物洒落效果
giftView = (GiftView) findViewById(R.id.gift);
// 获取当前屏幕的高宽
DisplayMetrics dm = new DisplayMetrics();
getWindowManager().getDefaultDisplay().getMetrics(dm);
giftView.SetView(dm.heightPixels, dm.widthPixels);
// 不断更新礼物
update();
}
public void update() {
giftView.produceGiftRandom(GIFTCOUNT);
//发送延迟消息
mHandler.sendEmptyMessageDelayed(1, 100);
}
@Override
protected void onDestroy() {
super.onDestroy();
//此处我们简洁化,当activity退出时就直接停止音乐的播放
intent.putExtra("action", "stop");
startService(intent);
stopService(intent);
}
}
好了,带闪烁效果的礼物下落也实现了。
三、自定义TextView实现跑马灯效果展示文本
自定义TextView:
- public class MyTextView extends TextView {
- public MyTextView(Context context) {
- super(context);
- }
- public MyTextView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public MyTextView(Context context, AttributeSet attrs, int defStyle) {
- super(context, attrs, defStyle);
- }
- //关键在这
- @Override
- public boolean isFocused() {
- return true;
- }
- }
public class MyTextView extends TextView {
public MyTextView(Context context) {
super(context);
}
public MyTextView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyTextView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
//关键在这
@Override
public boolean isFocused() {
return true;
}
}
在布局中使用,并进行相关设置(如无限循环滚动等)
- <!--跑马灯效果-->
- <com.chrismas.shiyu.mychristmas.view.MyTextView
- android:layout_width="230dp"
- android:layout_height="wrap_content"
- android:layout_centerHorizontal="true"
- android:layout_marginTop="20dp"
- android:ellipsize="marquee"
- android:marqueeRepeatLimit="marquee_forever"
- android:singleLine="true"
- android:text="Hello,我是诗雨!在这里祝大家圣诞快乐,开心快乐每一天!"
- android:textColor="#009900"
- android:textSize="18sp" />
<!--跑马灯效果-->
<com.chrismas.shiyu.mychristmas.view.MyTextView
android:layout_width="230dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_marginTop="20dp"
android:ellipsize="marquee"
android:marqueeRepeatLimit="marquee_forever"
android:singleLine="true"
android:text="Hello,我是诗雨!在这里祝大家圣诞快乐,开心快乐每一天!"
android:textColor="#009900"
android:textSize="18sp" />
其实跑马灯效果的实现也可以不用自定义TextView,只要在代码中在进行相关设置就可以了。但是我个人比较喜欢用自定义。
后记:
我也深知自己是Android界的小菜鸟,还有好多东西需要去学习。
也希望各位前辈多多指教,我一定虚心接纳并认真地进行改正!