Android 自定义View修炼-自定义弹幕效果View
一、概述
现在有个很流行的效果就是弹幕效果,满屏幕的文字从右到左飘来飘去。看的眼花缭乱,看起来还蛮cool的
现在就是来实现这一的一个效果,大部分的都是从右向左移动漂移,本文的效果中也支持从左向右的漂移移动
效果,同时也支持屏幕弹幕最多显示个数的设置。
二、效果图
废话不说,先来看看效果图吧~~
三、实现原理方案
1、自定义ViewGroup-XCDanmuView,继承RelativeLayout来实现,当然也可以继承其他三大布局类哈
2、初始化若干个TextView(弹幕的item View,这里以TextView 为例,当然也可以其他了~),然后通过addView添加到自定义View中
3、通过addView添加到XCDanmuView中,位置在坐标,为了实现 从屏幕外移动进来的效果
我们还需要修改添加进来TextView的位置,以从右向左移动方向来说,addView后必须将该TextView的位置设置到右边的屏幕外
这样我们采用的方法,是在onLayout()方法中对childView进行layout重新布局设置位置
4、随机冲左侧或右侧出来弹幕itemView,移动采用属性动画来实现平移,从屏幕的一端移动到另一端,当动画结束后,就将
该child从XCDanmuView中remove掉。并重新new 一个弹幕itemView ,并addView到XCDanmuView中,并开始动画移动
5、本自定义弹幕View支持从左到右和从右到左两个方向,支持自定义设置屏幕弹幕最多显示个数。
四、自定义弹幕效果XCDanmuView的具体实现
1、初始化需要用到的数据变量
- private int mWidth;
- private int mScreenWidth;
- private List<View> mChildList;
- private boolean mIsWorking = false;
- private Context mContext;
- private int mMaxShowNum = 15;
- private int mRowNum = 4;
- private int[] mSpeeds = {
- 3000,4000,5000,6000
- };
- private int mDelayDuration = 500;
- private int[] mBgResIds = {
- R.drawable.bg_danmu0,
- R.drawable.bg_danmu1,
- R.drawable.bg_danmu2,
- R.drawable.bg_danmu3
- };
- private int[] mRowPos = {
- 150,140,160,150
- };
- private Random mRandom;
- private String[] mStrContents;
- public static enum XCDirection{
- FROM_RIGHT_TO_LEFT,
- FORM_LEFT_TO_RIGHT
- }
- public enum XCAction{
- SHOW,HIDE
- }
- private XCDirection mDirection = XCDirection.FROM_RIGHT_TO_LEFT;
- private void init() {
mScreenWidth = getScreenWidth();
mChildList = new ArrayList<>();
mRandom = new Random();
}
2、初始化若干个弹幕item view
- public void initDanmuItemViews(String[] strContents){
- mStrContents = strContents;
- for(int i = 0; i < mMaxShowNum; i ++){
- int index = mRandom.nextInt(100) % strContents.length;
- createDanmuView(i,strContents[index],false);
- }
- }
3、创建弹幕item view 并addView到XCDanmuView中
- public void createDanmuView(int index,String content,boolean reset){
- final TextView textView = new TextView(mContext);
- textView.setTextColor(Color.WHITE);
- int r = mRandom.nextInt(100) % mRowNum;
- textView.setBackgroundResource(mBgResIds[r]);
- textView.setText(content +"_"+ (index+1));
- RelativeLayout.LayoutParams lp = new LayoutParams(LayoutParams.WRAP_CONTENT,
- RelativeLayout.LayoutParams.WRAP_CONTENT);
- int row = mRandom.nextInt(100) % mRowNum;
- while(row == lastRow){
- row = mRandom.nextInt(100)% mRowNum;
- }
- int pos = mRandom.nextInt(100)% mRowNum;
- lp.topMargin = row * mRowPos[pos];
- lastRow = row;
- textView.setLayoutParams(lp);
- textView.setPadding(40, 2, 40, 2);
- this.addView(textView);
- if(reset){
- mChildList.set(index,textView);
- }else{
- mChildList.add(index,textView);
- }
- textView.setClickable(true);
- textView.setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View view) {
- Toast toast = Toast.makeText(mContext, textView.getText(), Toast.LENGTH_SHORT);
- toast.setGravity(Gravity.TOP,0,50);
- toast.show();
- }
- });
- }
4、重新设置childView的初始位置到屏幕之外
- @Override
- protected void onLayout(boolean changed, int l, int t, int r, int b) {
- super.onLayout(changed, l, t, r, b);
- int childCount = this.getChildCount();
- for(int i=0;i<childCount;i++){
- View view = getChildAt(i);
- RelativeLayout.LayoutParams lp = (LayoutParams) view.getLayoutParams();
- if(lp.leftMargin <= 0){
- if(mDirection == XCDirection.FORM_LEFT_TO_RIGHT){
- view.layout(-view.getMeasuredWidth(), lp.topMargin,
- 0,lp.topMargin + view.getMeasuredHeight());
- }else{
- view.layout(mScreenWidth,lp.topMargin,mScreenWidth+view.getMeasuredWidth(),
- lp.topMargin+view.getMeasuredHeight());
- }
- }else{
- continue;
- }
- }
- }
5、弹幕item view的移动效果
- private Handler mHandler = new Handler() {
- @Override
- public void handleMessage(final Message msg) {
- super.handleMessage(msg);
- final int pos = msg.what;
- ViewPropertyAnimator animator;
- if(mDirection == XCDirection.FROM_RIGHT_TO_LEFT){
- animator = mChildList.get(msg.what).animate()
- .translationXBy(-(mScreenWidth + mChildList.get(msg.what).getWidth()));
- }else{
- animator = mChildList.get(msg.what).animate()
- .translationXBy(mScreenWidth + mChildList.get(msg.what).getWidth());
- }
- Random random = new Random(System.currentTimeMillis());
- int index = random.nextInt(100) % mSpeeds.length;
- animator.setDuration(mSpeeds[index]);
- animator.setInterpolator(new LinearInterpolator());
- animator.setListener(new Animator.AnimatorListener() {
- @Override
- public void onAnimationStart(Animator animator) {
- }
- @Override
- public void onAnimationEnd(Animator animator) {
- XCDanmuView.this.removeView(mChildList.get(pos));
- int index = mRandom.nextInt(100) % mStrContents.length;
- createDanmuView(pos, mStrContents[index], true);
- mHandler.sendEmptyMessageDelayed(pos, mDelayDuration);
- Log.v("czm", "size=" + mChildList.size());
- }
- @Override
- public void onAnimationCancel(Animator animator) {
- }
- @Override
- public void onAnimationRepeat(Animator animator) {
- }
- });
- animator.start();
- }
- };
6、开启弹幕效果和关闭弹幕效果以及对于的动画效果
- boolean isFirst = true;
- public void start(){
- switchAnimation(XCAction.SHOW);
- if(isFirst){
- for(int i =0;i< mChildList.size();i++){
- mHandler.sendEmptyMessageDelayed(i,i * mDelayDuration);
- }
- isFirst = false;
- }
- mIsWorking = true;
- }
- public void hide(){
- switchAnimation(XCAction.HIDE);
- mIsWorking =false;
- }
- public void stop(){
- this.setVisibility(View.GONE);
- for(int i =0;i< mChildList.size();i++){
- mChildList.get(i).clearAnimation();
- mHandler.removeMessages(i);
- }
- mIsWorking =false;
- }
- private void switchAnimation(final XCAction action){
- AlphaAnimation animation;
- if(action == XCAction.HIDE){
- animation = new AlphaAnimation(1.0f,0.0f);
- animation.setDuration(400);
- }else{
- animation = new AlphaAnimation(0.0f,1.0f);
- animation.setDuration(1000);
- }
- XCDanmuView.this.startAnimation(animation);
- animation.setAnimationListener(new Animation.AnimationListener() {
- @Override
- public void onAnimationStart(Animation animation) {
- }
- @Override
- public void onAnimationEnd(Animation animation) {
- if(action == XCAction.HIDE){
- XCDanmuView.this.setVisibility(View.GONE);
- }else{
- XCDanmuView.this.setVisibility(View.VISIBLE);
- }
- }
- @Override
- public void onAnimationRepeat(Animation animation) {
- }
- });
- }
五、如何使用该自定义侧滑View控件
使用该自定义View非常简单,控件默认效果从右向左,如果需要修改方向为从左到右,只需设置下方向即可
- public class MainActivity extends Activity {
- private XCDanmuView mDanmuView;
- private List<View> mViewList;
- private String[] mStrItems = {
- "搜狗","百度",
- "腾讯","360",
- "阿里巴巴","搜狐",
- "网易","新浪",
- "搜狗-上网从搜狗开始","百度一下,你就知道",
- "必应搜索-有求必应","好搜-用好搜,特顺手",
- "Android-谷歌","IOS-苹果",
- "Windows-微软","Linux"
- };
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- initDanmuView();
- initListener();
- }
- private void initListener() {
- findViewById(R.id.btn).setOnClickListener(new View.OnClickListener() {
- @Override
- public void onClick(View view) {
- if (mDanmuView.isWorking()) {
- mDanmuView.hide();
- ((Button) view).setText("开启弹幕");
- } else {
- mDanmuView.start();
- ((Button) view).setText("关闭弹幕");
- }
- }
- });
- }
- private void initDanmuView() {
- mDanmuView = (XCDanmuView)findViewById(R.id.danmu);
- mDanmuView.initDanmuItemViews(mStrItems);
- }
- }
六、源码下载
源码下载:http://www.demodashi.com/demo/13441.html
真题园网:http://www.zhentiyuan.com
Android 自定义View修炼-自定义弹幕效果View的更多相关文章
- Android 自定义View修炼-自定义HorizontalScrollView视图实现仿ViewPager效果
开发过程中,需要达到 HorizontalScrollView和ViewPager的效果,于是直接重写了HorizontalScrollView来达到实现ViewPager的效果. 实际效果图如下: ...
- Android 自定义View修炼-自定义View-带百分比进度的圆形进度条(采用自定义属性)
很多的时候,系统自带的View满足不了我们功能的需求,那么我们就需要自己来自定义一个能满足我们需求的View,自定义View我们需要先继承View,添加类的构造方法,重写父类View的一些方法,例如o ...
- Android 自定义View修炼-自定义可动画展开收缩View的实现
有时候需要点击一个view可以动画展开和收缩折叠一个View这样的效果,这样就可以直接自定义View来实现. 本例中,采用继承FrameLayout来实现自定义的ExpandView.下面将详细介绍各 ...
- Android 自定义View修炼-自定义加载进度动画XCLoadingImageView
一.概述 本自定义View,是加载进度动画的自定义View,继承于ImageView来实现,主要实现蒙层加载进度的加载进度效果. 支持水平左右加载和垂直上下加载四个方向,同时也支持自定义蒙层进度颜色. ...
- Android 自定义View修炼-【2014年最后的分享啦】Android实现自定义刮刮卡效果View
一.简介: 今天是2014年最后一天啦,首先在这里,我祝福大家在新的2015年都一个个的新健康,新收入,新顺利,新如意!!! 上一偏,我介绍了用Xfermode实现自定义圆角和椭圆图片view的博文& ...
- Android 自定义View修炼-打造完美的自定义侧滑菜单/侧滑View控件
一.概述 在App中,经常会出现侧滑菜单,侧滑滑出View等效果,虽然说Android有很多第三方开源库,但是实际上 咱们可以自己也写一个自定义的侧滑View控件,其实不难,主要涉及到以下几个要点: ...
- Android 自定义View修炼-Android 实现自定义的卫星式菜单(弧形菜单)View
一.总述 Android 实现卫星式菜单也叫弧形菜单的主要要做的工作如下:1.动画的处理2.自定义ViewGroup来实现卫星式菜单View (1)自定义属性 a. 在attrs.xml中 ...
- Android 自定义View修炼-仿360手机卫士波浪球进度的实现
像360卫士的波浪球进度的效果,一般最常用的方法就是 画线的方式,先绘sin线或贝塞尔曲线,然后从左到右绘制竖线,然后再裁剪圆区域. 今天我这用图片bitmap的方式,大概的方法原理是: (1)首先用 ...
- Android 自定义View修炼-Android开发之自定义View开发及实例详解
在开发Android应用的过程中,难免需要自定义View,其实自定义View不难,只要了解原理,实现起来就没有那么难. 其主要原理就是继承View,重写构造方法.onDraw,(onMeasure)等 ...
随机推荐
- SharePoint 2010 master page 控件介绍(1)
转:http://blog.csdn.net/lgm97/article/details/6409204 以下所有的内容都是根据Randy Drisgill (MVP SharePoint Serve ...
- UPC OJ 一道水题 STL
Problem C: 字符串游戏 Time Limit: 1 Sec Memory Limit: 128 MB Submit: 10 Solved: 3 [Submit][Status][Web ...
- java 注解(转)
第一部分:了解一下java1.5起默认的三个annotation类型: 一个是@Override:只能用在方法之上的,用来告诉别人这一个方法是改写父类的. 一个是@Deprecated:建 ...
- Android UI -- 的基础知识。
在介绍基础知识之前先明确几个基本的概念 View 视图是所有可视组件的基类,所有的UI控件包括布局类都是从View派生出来的. ViewGroup ViewGroup是View的扩展,可以放置多个Vi ...
- 专门为公共部门和联邦机构所设计Microsoft Azure
微软正式发布Microsoft Azure for Government,该云平台专门为公共部门和联邦机构所设计. 在2014年三月微软联邦执行官论坛上宣布的Microsoft Azure for G ...
- HW6.9
import java.util.Scanner; public class Solution { public static void main(String[] args) { Scanner i ...
- QQMusic绿钻兄,你可安好?我需要晴天。
不好意思,年纪这样大了,还依靠吐槽来保持呆毛的正能量,实在对不住,先说对不起. QQMusic是我最喜欢的腾讯增值服务,正版内容,海量歌手,高清下载.实在是音乐软件中高大上的典范,除了歌手排名中前十中 ...
- 科大讯飞和Tizen-TTS语音合成引擎
最近在做一个文本转语音TTS(Text to Speech)的第三方软件封装,使用的是国内语音技术龙头安徽科大讯飞公司提供的离线引擎AiSound5.0,主要用于汽车导航用途.科大讯飞还提供 了AiT ...
- 问题-WIN7 ..\Bin\InitCC32.exe".进程无法访问(拒绝访问)
问题现象: 问题原因:是InitCC32.exe没有权限. 问题处理:在DELPHI7的安装目录里设置用户权限,加入EVE... 这个用户.
- Linux Pmap 命令:查看进程用了多少内存
Pmap 提供了进程的内存映射,pmap命令用于显示一个或多个进程的内存状态.其报告进程的地址空间和内存状态信息.Pmap实际上是一个Sun OS上的命令,linux仅支持其有限的功能.但是它还是对查 ...