模拟视频播放器控制界面时动画效果出现的问题

原创 2013年12月01日 20:50:47

需求:

项目要实现一个类似视频播放器控制界面的效果,不过比他简单些,显示有三个部分组成:最上面进行时间和下面的两个控制按钮,点击后屏幕显示,过几秒自动消失。

首先想到的就是前几天刚看的MediaController,所以就把MediaController拿过来简单的看了下,想貌似没有它复杂,赶进度要紧,自己简单实现就好,最后效果如下:



实现思路:

自定义一个view,上面是一个显示时间的文本,设下透明度;下面用一个FrameLayout,先放纵向放两个线性布局在最底层实现下面白条效果,然后把两个文本按钮加在上层;最后在稍微加点进入和退出的动画效果(这个地方出了点粗心的问题,下面提到)。


实现:

首先是自定义view:

public class VideoControlPanel extends FrameLayout implements IVideoControlPanel, AnimationListener, OnTouchListener,
		Runnable {
	private static final int DELAYMILLIS = 3 * 1000;
	private static final int DURATION = 300;

	private boolean isShowing = false;

	private Animation topEnter, topExit, buttomEnter, buttomExit;

	private View mRoot;
	private TextView tvTitle;
	private LinearLayout llTitle, llChange, llHangup;
	private FrameLayout flOperate;

	private Handler handler = new Handler();

	public VideoControlPanel(Context context) {
		super(context);
		initControllerPanel();
	}

	public VideoControlPanel(Context context, AttributeSet attrs) {
		super(context, attrs);
		initControllerPanel();
	}

	private void initControllerPanel() {
		initOther();
		initView();
	}

	private void initView() {

		LayoutInflater inflate = (LayoutInflater) getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
		mRoot = inflate.inflate(R.layout.media_controller, null);

		llTitle = (LinearLayout) mRoot.findViewById(R.id.llTitle);
		flOperate = (FrameLayout) mRoot.findViewById(R.id.flOperate);

		tvTitle = (TextView) mRoot.findViewById(R.id.tvTitle);
		llHangup = (LinearLayout) mRoot.findViewById(R.id.llHangup);
		llChange = (LinearLayout) mRoot.findViewById(R.id.llChange);

		setOnTouchListener(this);

		addView(mRoot);

		show();
	}

	private void initOther() {
		topEnter = new TranslateAnimation(0, 0, -100, 0);
		topEnter.setDuration(DURATION);

		topExit = new TranslateAnimation(0, 0, 0, -100);
		topExit.setDuration(DURATION);
		topExit.setAnimationListener(this);

		buttomEnter = new TranslateAnimation(0, 0, 300, 0);
		buttomEnter.setDuration(DURATION);

		buttomExit = new TranslateAnimation(0, 0, 0, 100);
		buttomExit.setDuration(DURATION);
	}

	@Override
	public void onAnimationStart(Animation animation) {

	}

	@Override
	public void onAnimationEnd(Animation animation) {
		if (mRoot != null) {
			mRoot.setVisibility(View.GONE);
		}
	}

	@Override
	public void onAnimationRepeat(Animation animation) {

	}

	@Override
	public void hide() {
		isShowing = false;
		llTitle.startAnimation(topExit);
		flOperate.startAnimation(buttomExit);
	}

	@Override
	public void show() {
		if (!isShowing) {
			mRoot.setVisibility(View.VISIBLE);
			isShowing = true;

			llTitle.startAnimation(topEnter);

			flOperate.setAnimation(buttomEnter);
		}
		handler.removeCallbacks(this);
		handler.postDelayed(this, DELAYMILLIS);
	}

	@Override
	public void run() {
		hide();
	}

	@Override
	public void setTitle(String title) {
		if (tvTitle != null) {
			tvTitle.setText(title);
		}
	}

	@Override
	public View getHangupView() {
		return llHangup;
	}

	@Override
	public View getChangeView() {
		return llChange;
	}

	@Override
	public void setOnClickListener(OnClickListener listener) {
		// super.setOnClickListener(l);
		if (llHangup != null) {
			llHangup.setOnClickListener(listener);
		}
		if (llChange != null) {
			llChange.setOnClickListener(listener);
		}
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		show();
		return false;
	}
}

interface IVideoControlPanel {

	/**
	 * 隐藏操作面板
	 */
	public void hide();

	/**
	 * 显示操作面板
	 */
	public void show();

	/**
	 * 设置标题
	 * 
	 * @param title
	 */
	public void setTitle(String title);

	/**
	 * 获取挂断的View
	 * 
	 * @return
	 */
	public View getHangupView();

	/**
	 * 获取切换的View
	 * 
	 * @return
	 */
	public View getChangeView();
}
代码比较简单,所以也就没写注释。先加载xml中定义的布局,然后处理touch事件,最后用一个handle处理界面的消失。下面是布局文件:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical" >

    <LinearLayout
        android:id="@+id/llTitle"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:background="#88FFFFFF"
        android:gravity="center"
        android:orientation="horizontal"
        android:padding="8dip" >

        <TextView
            android:id="@+id/tvTitle"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:gravity="center_horizontal"
            android:text="通话时间:15分27秒"
            android:textSize="14sp" />
    </LinearLayout>

    <FrameLayout
        android:id="@+id/flOperate"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_alignParentBottom="true"
        android:orientation="horizontal" >

        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:orientation="vertical" >

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:src="#00FFFFFF" />

            <ImageView
                android:layout_width="match_parent"
                android:layout_height="40dp"
                android:src="#88FFFFFF" />
        </LinearLayout>

        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginTop="12dp" >

            <LinearLayout
                android:id="@+id/llHangup"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentLeft="true"
                android:layout_marginLeft="42dp"
                android:orientation="vertical" >

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:drawablePadding="4dp"
                    android:drawableTop="@drawable/ic_hangup"
                    android:gravity="center"
                    android:text="挂断" />
            </LinearLayout>

            <LinearLayout
                android:id="@+id/llChange"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_alignParentRight="true"
                android:layout_marginRight="42dp"
                android:orientation="vertical" >

                <TextView
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:drawablePadding="4dp"
                    android:drawableTop="@drawable/ic_change"
                    android:gravity="center"
                    android:text="切换" />
            </LinearLayout>
        </RelativeLayout>
    </FrameLayout>

</RelativeLayout>
这个布局的实现思路如上所述。然后就可以使用了,在需要的地方做如下引用:
<com.ttdevs.customcontrolpanel.VideoControlPanel
        android:id="@+id/vcpPanel"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:layout_alignParentTop="true"
        android:background="@drawable/bg" />
这样就完成了所需效果。

遇到的问题:

在弄动画的时候,出了点问题,折腾了好久,现象为:底部的按钮出现的动画只有程序第一次启动的时候有效,之后就再没效果了。由于对动画不熟悉,也不知道怪什么,开始是像上面那么写的,最后实在没办法做如下修改,即每次都创建buttomEnter,竟然解决问题了:

	@Override
	public void show() {
		if (!isShowing) {
			mRoot.setVisibility(View.VISIBLE);
			isShowing = true;

			llTitle.startAnimation(topEnter);

			buttomEnter = new TranslateAnimation(0, 0, 300, 0);
			buttomEnter.setDuration(DURATION);
			flOperate.setAnimation(buttomEnter);
		}
		handler.removeCallbacks(this);
		handler.postDelayed(this, DELAYMILLIS);
	}

虽然效果实现了,但是一直纠结这个动画问题出在哪里。今天整理的时候无意中发现竟然是自己调用有问题导致的:

flOperate.setAnimation(buttomEnter);应该改成:flOperate.startAnimation(buttomEnter);

这样问题就解决了。


最新修改:2013-12-09

上面的问题虽然坚决了,却不知道问题出在哪,为什么解决,今天无意中看到一篇文章(来自:wangjinyu501),又拿过来研究了下,

public void setAnimation (Animation animation)

Added in API level 1

Sets the next animation to play for this view. If you want the animation to play immediately, use startAnimation(android.view.animation.Animation) instead. This method provides allows fine-grained control over the start time and invalidation, but you must make sure that 1) the animation has a start time set, and 2) the view's parent (which controls animations on its children) will be invalidated when the animation is supposed to start.

Parameters
animation The next animation, or null.
其中提到,想立即启动动画可以使用startAnimation(Animation)。setAnimation允许细粒度的控制(动画的)启动时间和失效,但是这样必须满足两个条件1)设置了动画启动时间,2)执行动画的组件的父视图在动画启动之前需要刷新界面(从wangjinyu501引用来的)。分析下,第一次动画出问题应该是没有设置动画的启动时间,因此在setAnimation()之前加上:

buttomEnter.setStartTime(Animation.START_ON_FIRST_FRAME);
这样即可。那为什么每次都创建就可以播放动画呢,有兴趣可以看看setStartTime的源码或者打印下buttomEnter.hasStarted()的值。


去掉了布局文件后代码:

public class VideoControlPanel extends FrameLayout implements IVideoControlPanel, AnimationListener, OnTouchListener,
		Runnable {
	private static final int DELAYMILLIS = 3 * 1000; // 显示延时
	private static final int DURATION = 300; // 动画持续

	private boolean isShowing = false;

	private Animation topEnter, topExit, buttomEnter, buttomExit;
	private View mRoot;
	private TextView tvTitle;
	private RelativeLayout rlParent, rlOperate;
	private LinearLayout llTitle, llChange, llHangup, llOperateBg;
	private FrameLayout flOperate;

	private Handler handler = new Handler();

	public VideoControlPanel(Context context) {
		super(context);
		initControllerPanel();
	}

	public VideoControlPanel(Context context, AttributeSet attrs) {
		super(context, attrs);
		initControllerPanel();
	}

	private void initControllerPanel() {
		initOther();
		initView();
	}

	private void initView() {
		mRoot = initCustomView();

		setOnTouchListener(this);

		addView(mRoot);

		show();
	}

	private View initCustomView() {
		rlParent = new RelativeLayout(getContext());
		rlParent.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));

		// 上部分
		llTitle = new LinearLayout(getContext());
		llTitle.setLayoutParams(new LayoutParams(LayoutParams.MATCH_PARENT, 60));
		llTitle.setOrientation(LinearLayout.VERTICAL);
		llTitle.setBackgroundColor(Color.parseColor("#90FFFFFF")); // TODO
		llTitle.setGravity(Gravity.CENTER);
		tvTitle = new TextView(getContext());
		tvTitle.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		tvTitle.setGravity(Gravity.CENTER);
		tvTitle.setTextSize(18);
		llTitle.addView(tvTitle);

		RelativeLayout.LayoutParams rlpTop = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
				RelativeLayout.LayoutParams.WRAP_CONTENT);
		rlpTop.addRule(RelativeLayout.ALIGN_PARENT_TOP);
		rlParent.addView(llTitle, rlpTop);

		// 下部分
		flOperate = new FrameLayout(getContext());
		flOperate.setLayoutParams(new FrameLayout.LayoutParams(FrameLayout.LayoutParams.MATCH_PARENT,
				FrameLayout.LayoutParams.WRAP_CONTENT));

		// 下部分背景
		llOperateBg = new LinearLayout(getContext());
		llOperateBg.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT,
				LinearLayout.LayoutParams.WRAP_CONTENT));
		llOperateBg.setOrientation(LinearLayout.VERTICAL);
		addBackgroundView("#00FFFFFF");
		addBackgroundView("#90FFFFFF");
		flOperate.addView(llOperateBg);

		// 下部分按钮
		rlOperate = new RelativeLayout(getContext());
		rlOperate.setLayoutParams(new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT,
				RelativeLayout.LayoutParams.MATCH_PARENT));

		// 下部分按钮挂断
		llHangup = getButtomLayout("挂断", R.drawable.ic_hangup);
		addBottomView(true, llHangup);

		// 下部分按钮切换
		llChange = getButtomLayout("切换", R.drawable.ic_change);
		addBottomView(false, llChange);

		flOperate.addView(rlOperate);

		RelativeLayout.LayoutParams rlpBottom = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT,
				LayoutParams.WRAP_CONTENT);
		rlpBottom.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
		rlParent.addView(flOperate, rlpBottom);
		return rlParent;
	}

	private void addBackgroundView(String color) {
		ImageView ivBg = new ImageView(getContext());
		ivBg.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, 80));
		ivBg.setBackgroundColor(Color.parseColor(color));
		llOperateBg.addView(ivBg);
	}

	private LinearLayout getButtomLayout(String text, int drawId) {
		LinearLayout llChange = new LinearLayout(getContext());
		llChange.setLayoutParams(new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
				LinearLayout.LayoutParams.WRAP_CONTENT));
		llChange.setOrientation(LinearLayout.VERTICAL);
		TextView tvChange = new TextView(getContext());
		tvChange.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
		tvChange.setText(text);
		tvChange.setTextSize(18);
		tvChange.setTextColor(Color.parseColor("#FF393939"));
		tvChange.setGravity(Gravity.CENTER);
		tvChange.setCompoundDrawablePadding(2);
		tvChange.setCompoundDrawablesWithIntrinsicBounds(null, getResources().getDrawable(drawId), null, null);
		llChange.addView(tvChange);
		return llChange;
	}

	private void addBottomView(boolean isLeft, LinearLayout view) {
		RelativeLayout.LayoutParams lp = new RelativeLayout.LayoutParams(LayoutParams.WRAP_CONTENT,
				LayoutParams.WRAP_CONTENT);
		lp.addRule(RelativeLayout.CENTER_VERTICAL);
		if (isLeft) {
			lp.addRule(RelativeLayout.ALIGN_PARENT_LEFT);
			lp.leftMargin = 88;
		} else {
			lp.addRule(RelativeLayout.ALIGN_PARENT_RIGHT);
			lp.rightMargin = 88;
		}
		rlOperate.addView(view, lp);
	}

	private void initOther() {
		topEnter = new TranslateAnimation(0, 0, -100, 0);
		topEnter.setDuration(DURATION);

		topExit = new TranslateAnimation(0, 0, 0, -100);
		topExit.setDuration(DURATION);
		topExit.setAnimationListener(this);

		buttomEnter = new TranslateAnimation(0, 0, 300, 0);
		buttomEnter.setDuration(DURATION);

		buttomExit = new TranslateAnimation(0, 0, 0, 100);
		buttomExit.setDuration(DURATION);
	}

	@Override
	public void onAnimationStart(Animation animation) {
		// do nothing
	}

	@Override
	public void onAnimationEnd(Animation animation) {
		if (mRoot != null) {
			mRoot.setVisibility(View.GONE);
		}
	}

	@Override
	public void onAnimationRepeat(Animation animation) {
		// do nothing
	}

	@Override
	public void hide() {
		isShowing = false;
		llTitle.startAnimation(topExit);
		flOperate.startAnimation(buttomExit);
	}

	@Override
	public void show() {
		if (!isShowing) {
			mRoot.setVisibility(View.VISIBLE);
			isShowing = true;

			llTitle.startAnimation(topEnter);
			
			flOperate.startAnimation(buttomEnter);
		}
		handler.removeCallbacks(this);
		handler.postDelayed(this, DELAYMILLIS);
	}

	@Override
	public void run() {
		hide();
	}

	@Override
	public void setTitle(String title) {
		if (tvTitle != null) {
			tvTitle.setText(title);
		}
	}

	@Override
	public View getHangupView() {
		return llHangup;
	}

	@Override
	public View getChangeView() {
		return llChange;
	}

	@Override
	public boolean onTouch(View v, MotionEvent event) {
		show();
		return false;
	}
}

interface IVideoControlPanel {

	/**
	 * 隐藏操作面板
	 */
	public void hide();

	/**
	 * 显示操作面板
	 */
	public void show();

	/**
	 * 设置标题
	 * 
	 * @param title
	 */
	public void setTitle(String title);

	/**
	 * 获取挂断的View
	 * 
	 * @return
	 */
	public View getHangupView();

	/**
	 * 获取切换的View
	 * 
	 * @return
	 */
	public View getChangeView();
}




版权声明:本文为博主原创文章,未经博主允许不得转载。

Freesacle主板方案,CVBS四路模拟视频主板,仪器|仪表|数据采集|数据分析|信号控制|硬件定制,单片机

产品描述: LTFX6-Core系列核心板是我公司基于NXP(Freesacle) i.MX 6 系列应用处理器研发设计的,是一个可运行Android、Linux系统的最小硬件平台;其中处理器i....

Qt之界面出现、消失动画效果

(2013-01-18 10:03:33) 转载▼   分类: Qt     在学习Qt的这2、3个月里,对Qt越发感兴趣,从刚开始的盲目、无所适...

Qt之界面出现、消失动画效果

http://blog.sina.com.cn/s/blog_a6fb6cc90101awhm.html 在学习Qt的这2、3个月里,对Qt越发感兴趣,从刚开始的盲目、无所适从到现在的学习、...

有动画效果的启动界面

  • 2016年01月27日 12:11
  • 2.61MB
  • 下载

Activity切换结合动画效果出现白屏的问题

android的动画简介

Android界面切换动画效果源代码

  • 2013年10月12日 23:35
  • 1.44MB
  • 下载
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:模拟视频播放器控制界面时动画效果出现的问题
举报原因:
原因补充:

(最多只允许输入30个字)