android 动态背景的实现以及SurfaceView中添加EditText控件

首先还是一贯作风,我们先看案例:

静态图看不出来效果,如果用过此软件(扎客)的同学们都知道,她的背景会动.怎么样,是不是觉得很时尚,起码比静态的要好(个人观点).其实实现起来并不复杂,这个如果让做游戏程序员做简直太小儿科了,这里我说明一点,其实我们做应用的也应该多少了解下游戏编程思维,起码对我们做应用有很好的帮助.

下面我简单介绍下实现方式.

实现原理:自定义一个SurfaceView控件.对之不停的onDraw,使得其背景动起来.

对于SurfaceView如果不了解的同学们麻烦你先上网查找下,网上相关介绍很多.

这里我简单介绍下其功能:首先这个控件是View的子类.好处就是可以在线程中(非UI线程)对UI进行更新.

MySurfaceView.java

  1. package com.jj.dynamic;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.Canvas;
  5. import android.graphics.Color;
  6. import android.graphics.Paint;
  7. import android.graphics.PorterDuff;
  8. import android.util.AttributeSet;
  9. import android.view.SurfaceHolder;
  10. import android.view.SurfaceView;
  11. import android.view.SurfaceHolder.Callback;
  12. public class MySurfaceView extends SurfaceView implements Callback, Runnable {
  13. private Context mContext;
  14. private SurfaceHolder surfaceHolder;
  15. private boolean flag = false;// 线程标识
  16. private Bitmap bitmap_bg;// 背景图
  17. private float mSurfaceWindth, mSurfaceHeight;// 屏幕宽高
  18. private int mBitposX;// 图片的位置
  19. private Canvas mCanvas;
  20. private Thread thread;
  21. // 背景移动状态
  22. private enum State {
  23. LEFT, RINGHT
  24. }
  25. // 默认为向左
  26. private State state = State.LEFT;
  27. private final int BITMAP_STEP = 1;// 背景画布移动步伐.
  28. public MySurfaceView(Context context, AttributeSet attrs) {
  29. super(context, attrs);
  30. flag = true;
  31. this.mContext = context;
  32. setFocusable(true);
  33. setFocusableInTouchMode(true);
  34. surfaceHolder = getHolder();
  35. surfaceHolder.addCallback(this);
  36. }
  37. /***
  38. * 进行绘制.
  39. */
  40. protected void onDraw() {
  41. drawBG();
  42. updateBG();
  43. }
  44. /***
  45. * 更新背景.
  46. */
  47. public void updateBG() {
  48. /** 图片滚动效果 **/
  49. switch (state) {
  50. case LEFT:
  51. mBitposX -= BITMAP_STEP;// 画布左移
  52. break;
  53. case RINGHT:
  54. mBitposX += BITMAP_STEP;// 画布右移
  55. break;
  56. default:
  57. break;
  58. }
  59. if (mBitposX <= -mSurfaceWindth / 2) {
  60. state = State.RINGHT;
  61. }
  62. if (mBitposX >= 0) {
  63. state = State.LEFT;
  64. }
  65. }
  66. /***
  67. * 绘制背景
  68. */
  69. public void drawBG() {
  70. mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);// 清屏幕.
  71. mCanvas.drawBitmap(bitmap_bg, mBitposX, 0, null);// 绘制当前屏幕背景
  72. }
  73. @Override
  74. public void run() {
  75. while (flag) {
  76. synchronized (surfaceHolder) {
  77. mCanvas = surfaceHolder.lockCanvas();
  78. onDraw();
  79. surfaceHolder.unlockCanvasAndPost(mCanvas);
  80. try {
  81. Thread.sleep(100);
  82. } catch (InterruptedException e) {
  83. e.printStackTrace();
  84. }
  85. }
  86. }
  87. }
  88. @Override
  89. public void surfaceCreated(SurfaceHolder holder) {
  90. mSurfaceWindth = getWidth();
  91. mSurfaceHeight = getHeight();
  92. int mWindth = (int) (mSurfaceWindth * 3 / 2);
  93. /***
  94. * 将图片缩放到屏幕的3/2倍.
  95. */
  96. bitmap_bg = BitmapUtil.ReadBitmapById(mContext, R.drawable.hypers_bg,
  97. (int) mWindth, (int) mSurfaceHeight);
  98. thread = new Thread(this);
  99. thread.start();
  100. }
  101. @Override
  102. public void surfaceChanged(SurfaceHolder holder, int format, int width,
  103. int height) {
  104. }
  105. @Override
  106. public void surfaceDestroyed(SurfaceHolder holder) {
  107. flag = false;
  108. }
  109. }
package com.jj.dynamic;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.util.AttributeSet;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.SurfaceHolder.Callback;

public class MySurfaceView extends SurfaceView implements Callback, Runnable {
	private Context mContext;
	private SurfaceHolder surfaceHolder;
	private boolean flag = false;// 线程标识
	private Bitmap bitmap_bg;// 背景图

	private float mSurfaceWindth, mSurfaceHeight;// 屏幕宽高

	private int mBitposX;// 图片的位置

	private Canvas mCanvas;

	private Thread thread;

	// 背景移动状态
	private enum State {
		LEFT, RINGHT
	}

	// 默认为向左
	private State state = State.LEFT;

	private final int BITMAP_STEP = 1;// 背景画布移动步伐.

	public MySurfaceView(Context context, AttributeSet attrs) {
		super(context, attrs);
		flag = true;
		this.mContext = context;
		setFocusable(true);
		setFocusableInTouchMode(true);
		surfaceHolder = getHolder();
		surfaceHolder.addCallback(this);
	}

	/***
	 * 进行绘制.
	 */
	protected void onDraw() {
		drawBG();
		updateBG();
	}

	/***
	 * 更新背景.
	 */
	public void updateBG() {
		/** 图片滚动效果 **/
		switch (state) {
		case LEFT:
			mBitposX -= BITMAP_STEP;// 画布左移
			break;
		case RINGHT:
			mBitposX += BITMAP_STEP;// 画布右移
			break;

		default:
			break;
		}
		if (mBitposX <= -mSurfaceWindth / 2) {
			state = State.RINGHT;
		}
		if (mBitposX >= 0) {
			state = State.LEFT;
		}
	}

	/***
	 * 绘制背景
	 */
	public void drawBG() {
		mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);// 清屏幕.
		mCanvas.drawBitmap(bitmap_bg, mBitposX, 0, null);// 绘制当前屏幕背景
	}

	@Override
	public void run() {
		while (flag) {
			synchronized (surfaceHolder) {
				mCanvas = surfaceHolder.lockCanvas();
				onDraw();
				surfaceHolder.unlockCanvasAndPost(mCanvas);
				try {
					Thread.sleep(100);
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}

	}

	@Override
	public void surfaceCreated(SurfaceHolder holder) {

		mSurfaceWindth = getWidth();
		mSurfaceHeight = getHeight();
		int mWindth = (int) (mSurfaceWindth * 3 / 2);
		/***
		 * 将图片缩放到屏幕的3/2倍.
		 */
		bitmap_bg = BitmapUtil.ReadBitmapById(mContext, R.drawable.hypers_bg,
				(int) mWindth, (int) mSurfaceHeight);

		thread = new Thread(this);
		thread.start();

	}

	@Override
	public void surfaceChanged(SurfaceHolder holder, int format, int width,
			int height) {

	}

	@Override
	public void surfaceDestroyed(SurfaceHolder holder) {
		flag = false;
	}

}
上诉代码相当简单,我也不过多介绍.相信大家都看得懂.

下面是我们只需要在Main.xml中引用即可.

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <com.jj.dynamic.MySurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
  3. android:layout_width="fill_parent"
  4. android:layout_height="fill_parent" >
  5. </com.jj.dynamic.MySurfaceView>
<?xml version="1.0" encoding="utf-8"?>
<com.jj.dynamic.MySurfaceView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

</com.jj.dynamic.MySurfaceView>
这个的效果图我就不展示了.就是一个时时变动的背景图片,下面我展示下我最近在开发的一个内部小型项目,针对开年会娱乐场所用的.(里面东西都是会动的.)看是简单我加了好多动画特效,做这个页面花了我一个星期呢.

怎么样,看起来还不错吧.其实我只是想说明一点.我们应用中完全可以把游戏融入进去,这样我们可以得到另一番景象,不过话说回来,这样也会带来相应的负面影响,因为都是画上去的,所以工作量也会翻倍.总之根据自己需要来开发就好了.

下面我上传下APK,大家可以下载安装下看看,说不定你可以从中找到灵感.

HypersParty.apk


下面我们再看一个页面:


我想说明的是这个密码后面的EditText的问题,要加上去很简单,我们直接可以通过布局搞定,下面我们看布局文件


这里我没有上布局文件代码,是因为我觉得看这个视图更好理解一点,不是么,有很多一上来就把布局文件啪啦啪啦贴出来,还得读取半天.

我说下诡异问题.看下面张图片:


这张图片是我点击键盘后让键盘小时候的结果(注:此时软键盘可以遮挡输入框).其实如果你再次点击edittext,其实它还在原位,只是surfaceView在绘制的时候影响到了,原因不明.(下面我说个更诡异的问题,真是一个接一个,弄的我有想摔手机的心都有了.我的测试机是华为S8600,android2.3的,然后我用oppo手机android4.0测试的时候用截图工具竟然截不出来上面这张bug图片,手机助手显示是OK,但是手机上显示是BUG,NND,当时郁闷的要死,不管了这也不是重点.)

解决方法很简单:我们只需要在我们的activity中执行这段话就ok了.(同样适用于自定义的dialog.)

  1. getWindow().setSoftInputMode(
  2. WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
  3. | WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
		getWindow().setSoftInputMode(
				WindowManager.LayoutParams.SOFT_INPUT_ADJUST_RESIZE
						| WindowManager.LayoutParams.SOFT_INPUT_STATE_HIDDEN);
网上有的说可以在配置文件中配置,可是我配置了竟然无动于衷.大家可以去研究研究,总之代码这种方案可行.

效果图:



问题又出来了,看着怎么这么别扭呢,为什么密码跑了那么高呢?

这个问题没有解决,希望同学们有解决方案的朋友们麻烦告知下,(尝试多次不行,个人感觉系统是以edittext为对象,将之弹起,中间的距离和edittext本身在布局中的位置有关,如果在底部的话,那么正好在键盘的上面)。

有文章说 getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_ADJUST_PAN); 这句话可以解决,可惜试了试不尽人意.


总之看着还说的过去,临时就这样了,昨天在群里问了问,有朋友们提出,弄一个透明的dialog,activity,想想虽然没有这么搞的,但是确实可行,只要你处理得好,根本看不出来他们不是一个布局.


最后简单说明一点:其实在surfaceView中一般不需要加edittext控件的,比如说游戏,即使要的话,也会弹出一个性感的dialog.在其中加载控件(尤其是edittext)几乎就不会有这样的需求,即使有了,我们换个思维实现就OK了.

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
要在Android动态添加SurfaceView,您需要执行以下步骤: 1. 创建一个自定义视图类,继承SurfaceView实现相关的方法。 2. 在您的活动或片段创建一个视图组,例如LinearLayout,以用于容纳SurfaceView。 3. 在您的活动或片段实例化自定义视图类,并将其添加到视图组。 以下是一个简单的示例代码,演示如何动态添加SurfaceView到LinearLayout: ``` public class MySurfaceView extends SurfaceView implements SurfaceHolder.Callback { private SurfaceHolder holder; public MySurfaceView(Context context) { super(context); holder = getHolder(); holder.addCallback(this); } @Override public void surfaceCreated(SurfaceHolder holder) { // 初始化绘制线程等相关操作 } @Override public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) { // 视图大小发生改变时的处理 } @Override public void surfaceDestroyed(SurfaceHolder holder) { // 停止绘制线程等相关操作 } } public class MainActivity extends AppCompatActivity { private LinearLayout layout; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); layout = findViewById(R.id.surface_container); MySurfaceView surfaceView = new MySurfaceView(this); LinearLayout.LayoutParams params = new LinearLayout.LayoutParams( LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); layout.addView(surfaceView, params); } } ``` 在上面的示例,MySurfaceView类继承了SurfaceView实现了SurfaceHolder.Callback接口,以便在创建、大小更改和销毁SurfaceView时执行适当的操作。MainActivity类包含一个LinearLayout视图组,它具有一个ID为surface_container的布局元素。在onCreate方法,我们实例化MySurfaceView类,并将其添加到LinearLayout视图组。 请注意,您可以使用不同的布局元素和布局参数来容纳SurfaceView。此外,您可以根据需要对MySurfaceView类进行自定义,以实现您的特定需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值