本文为个人原创,欢迎转载,但请务必在明显位置注明出处!

GitHub地址:https://github.com/motianhuo/wechat

微信从6.0版本开始推出小视频功能,随着4G网络的出现,视频将会是一个趋势,他能表达出文字所不能表现的东西,增加了微信的黏性。还记得微信小视频这个功能一推出,如同病毒一样席卷朋友圈。

作为爱美的我们,怎么能把我们的窘态暴露给朋友圈的小伙伴呢,必须正能量!美好的!必须美化! So,录制小视频后,加各种滤镜,炫酷MV主题,妈妈再也不担心我的猪窝了…

“小视频”对于微信如此之重要。那么,如何实现呢?
先看下咱们的实现效果:

PS:gif 图片比较大,如果等不及的童鞋,可以点击这里查看视频

OK,先看下,消息列表页面的 下滑显示眼睛动画效果的实现方式:
自定义ListView:PullDownListView.java
PullDownListView来自guojunyi的分享, GitHub项目地址:点击这里

package com.example.wechat01.widght;import android.content.Context;
import android.graphics.Color;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.AbsListView;
import android.widget.AbsListView.OnScrollListener;
import android.widget.ListView;
import android.widget.RelativeLayout;import com.example.wechat01.R;
import com.nineoldandroids.animation.ValueAnimator;
import com.nineoldandroids.animation.ValueAnimator.AnimatorUpdateListener;public class PullDownListView extends RelativeLayout implementsOnScrollListener {static int MAX_PULL_TOP_HEIGHT;static int MAX_PULL_BOTTOM_HEIGHT;static int REFRESHING_TOP_HEIGHT;static int REFRESHING_BOTTOM_HEIGHT;private boolean isTop;private boolean isBottom;private boolean isRefreshing;private boolean isAnimation;RelativeLayout layoutHeader;RelativeLayout layoutFooter;private int mCurrentY = 0;boolean pullTag = false;OnScrollListener mOnScrollListener;OnPullHeightChangeListener mOnPullHeightChangeListener;public void setOnPullHeightChangeListener(OnPullHeightChangeListener listener) {this.mOnPullHeightChangeListener = listener;}public void setOnScrollListener(OnScrollListener listener) {mOnScrollListener = listener;}public PullDownListView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stub}public boolean isRefreshing() {return this.isRefreshing;}private ListView mListView = new ListView(getContext()) {int lastY = 0;@Overridepublic boolean onTouchEvent(MotionEvent ev) {if (isAnimation || isRefreshing) {return super.onTouchEvent(ev);}RelativeLayout parent = (RelativeLayout) mListView.getParent();int currentY = (int) ev.getRawY();switch (ev.getAction()) {case MotionEvent.ACTION_DOWN:lastY = (int) ev.getRawY();break;case MotionEvent.ACTION_MOVE: {boolean isToBottom = currentY - lastY >= 0 ? true : false;int step = Math.abs(currentY - lastY);lastY = currentY;if (isTop && mListView.getTop() >= 0) {if (isToBottom && mListView.getTop() <= MAX_PULL_TOP_HEIGHT) {MotionEvent event = MotionEvent.obtain(ev);ev.setAction(MotionEvent.ACTION_UP);super.onTouchEvent(ev);pullTag = true;if (mListView.getTop() > layoutHeader.getHeight()) {step = step / 2;}if ((mListView.getTop() + step) > MAX_PULL_TOP_HEIGHT) {mCurrentY = MAX_PULL_TOP_HEIGHT;scrollTopTo(mCurrentY);} else {mCurrentY += step;scrollTopTo(mCurrentY);}} else if (!isToBottom && mListView.getTop() > 0) {MotionEvent event = MotionEvent.obtain(ev);ev.setAction(MotionEvent.ACTION_UP);super.onTouchEvent(ev);if ((mListView.getTop() - step) < 0) {mCurrentY = 0;scrollTopTo(mCurrentY);} else {mCurrentY -= step;scrollTopTo(mCurrentY);}} else if (!isToBottom && mListView.getTop() == 0) {if (!pullTag) {return super.onTouchEvent(ev);}}return true;} else if (isBottom&& mListView.getBottom() <= parent.getHeight()) {if (!isToBottom&& (parent.getHeight() - mListView.getBottom()) <= MAX_PULL_BOTTOM_HEIGHT) {MotionEvent event = MotionEvent.obtain(ev);ev.setAction(MotionEvent.ACTION_UP);super.onTouchEvent(ev);pullTag = true;if (parent.getHeight() - mListView.getBottom() > layoutFooter.getHeight()) {step = step / 2;}if ((mListView.getBottom() - step) < (parent.getHeight() - MAX_PULL_BOTTOM_HEIGHT)) {mCurrentY = -MAX_PULL_BOTTOM_HEIGHT;scrollBottomTo(mCurrentY);} else {mCurrentY -= step;scrollBottomTo(mCurrentY);}} else if (isToBottom&& (mListView.getBottom() < parent.getHeight())) {if ((mListView.getBottom() + step) > parent.getHeight()) {mCurrentY = 0;scrollBottomTo(mCurrentY);} else {mCurrentY += step;scrollBottomTo(mCurrentY);}} else if (isToBottom&& mListView.getBottom() == parent.getHeight()) {if (!pullTag) {return super.onTouchEvent(ev);}}return true;}break;}case MotionEvent.ACTION_CANCEL:case MotionEvent.ACTION_UP:pullTag = false;if (mListView.getTop() > 0) {if (mListView.getTop() > REFRESHING_TOP_HEIGHT) {animateTopTo(layoutHeader.getMeasuredHeight());isRefreshing = true;if (null != mOnPullHeightChangeListener) {mOnPullHeightChangeListener.onRefreshing(true);}} else {animateTopTo(0);}} else if (mListView.getBottom() < parent.getHeight()) {if ((parent.getHeight() - mListView.getBottom()) > REFRESHING_BOTTOM_HEIGHT) {animateBottomTo(-layoutFooter.getMeasuredHeight());isRefreshing = true;if (null != mOnPullHeightChangeListener) {mOnPullHeightChangeListener.onRefreshing(false);}} else {animateBottomTo(0);}}}return super.onTouchEvent(ev);}};public void scrollBottomTo(int y) {mListView.layout(mListView.getLeft(), y, mListView.getRight(),this.getMeasuredHeight() + y);if (null != mOnPullHeightChangeListener) {mOnPullHeightChangeListener.onBottomHeightChange(layoutHeader.getHeight(), -y);}}public void animateBottomTo(final int y) {ValueAnimator animator = ValueAnimator.ofInt(mListView.getBottom()- this.getMeasuredHeight(), y);animator.setDuration(300);animator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// TODO Auto-generated method stubint frameValue = (Integer) animation.getAnimatedValue();mCurrentY = frameValue;scrollBottomTo(frameValue);if (frameValue == y) {isAnimation = false;}}});isAnimation = true;animator.start();}public void scrollTopTo(int y) {mListView.layout(mListView.getLeft(), y, mListView.getRight(),this.getMeasuredHeight() + y);if (null != mOnPullHeightChangeListener) {mOnPullHeightChangeListener.onTopHeightChange(layoutHeader.getHeight(), y);}}public void animateTopTo(final int y) {ValueAnimator animator = ValueAnimator.ofInt(mListView.getTop(), y);animator.setDuration(300);animator.addUpdateListener(new AnimatorUpdateListener() {@Overridepublic void onAnimationUpdate(ValueAnimator animation) {// TODO Auto-generated method stubint frameValue = (Integer) animation.getAnimatedValue();mCurrentY = frameValue;scrollTopTo(frameValue);if (frameValue == y) {isAnimation = false;}}});isAnimation = true;animator.start();}@Overridepublic void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {super.onMeasure(widthMeasureSpec, heightMeasureSpec);REFRESHING_TOP_HEIGHT = layoutHeader.getMeasuredHeight();REFRESHING_BOTTOM_HEIGHT = layoutFooter.getMeasuredHeight();MAX_PULL_TOP_HEIGHT = this.getMeasuredHeight();MAX_PULL_BOTTOM_HEIGHT = this.getMeasuredHeight();}@Overridepublic void onFinishInflate() {mListView.setBackgroundColor(0xffffffff);mListView.setCacheColorHint(Color.TRANSPARENT);mListView.setVerticalScrollBarEnabled(false);mListView.setLayoutParams(new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT));mListView.setOnScrollListener(this);mListView.setDividerHeight(0);this.addView(mListView);layoutHeader = (RelativeLayout) this.findViewById(R.id.layoutHeader);layoutFooter = (RelativeLayout) this.findViewById(R.id.layoutFooter); super.onFinishInflate();}public ListView getListView() {return this.mListView;} public void pullUp() {isRefreshing = false;if (mListView.getTop() > 0) {animateTopTo(0);} else if (mListView.getBottom() < this.getHeight()) {animateBottomTo(0);} }@Overridepublic void onScroll(AbsListView view, int firstVisibleItem,int visibleItemCount, int totalItemCount) {// TODO Auto-generated method stubif (null != mOnScrollListener) {mOnScrollListener.onScroll(view, firstVisibleItem,visibleItemCount, totalItemCount);}if (mListView.getCount() > 0) {if ((firstVisibleItem + visibleItemCount) == totalItemCount) {View lastItem = (View) mListView.getChildAt(visibleItemCount - 1);if (null != lastItem) {if (lastItem.getBottom() == mListView.getHeight()) {Log.e("my", lastItem.getBottom() + "");isBottom = true;} else {isBottom = false;}}} else {isBottom = false;}} else {isBottom = false;}if (mListView.getCount() > 0) {if (firstVisibleItem == 0) {View firstItem = mListView.getChildAt(0);if (null != firstItem) {if (firstItem.getTop() == 0) {isTop = true;} else {isTop = false;}}} else {isTop = false;}} else {isTop = true;}}@Overridepublic void onScrollStateChanged(AbsListView view, int scrollState) {// TODO Auto-generated method stubif (null != mOnScrollListener) {mOnScrollListener.onScrollStateChanged(view, scrollState);}}// listener call backpublic interface OnPullHeightChangeListener {public void onTopHeightChange(int headerHeight, int pullHeight);public void onBottomHeightChange(int footerHeight, int pullHeight);public void onRefreshing(boolean isTop);}
}

再看,小眼睛的实现方式:EyeView.java

package com.example.wechat01.widght;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.Config;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.graphics.drawable.BitmapDrawable;
import android.os.Handler;
import android.util.AttributeSet;
import android.widget.ImageView;import com.example.wechat01.R;public class EyeView extends ImageView {Paint mPaint;float progress;boolean isAnimate;int rotateProgress;Handler mHandler = new Handler();public EyeView(Context context, AttributeSet attrs) {super(context, attrs);// TODO Auto-generated constructor stubmPaint = new Paint();mPaint.setAntiAlias(true);rotateProgress = 0;progress = 0.0f;}@Overridepublic void onDraw(Canvas canvas) {int minWidth = (int) (this.getWidth() * progress);int minHeight = (int) (this.getHeight() * progress);if (minWidth > 1 && minHeight > 1) {Bitmap bitmap = getBitmap();canvas.drawBitmap(bitmap, 0, 0, null);bitmap.recycle();}}public Bitmap getBitmap() {Bitmap origin1 = null;Bitmap origin2 = null;if (progress >= 1.0) {BitmapDrawable drawable1 = (BitmapDrawable) this.getResources().getDrawable(R.drawable.eye_light1);origin1 = drawable1.getBitmap();BitmapDrawable drawable2 = (BitmapDrawable) this.getResources().getDrawable(R.drawable.eye_light2);origin2 = drawable2.getBitmap();} else {BitmapDrawable drawable1 = (BitmapDrawable) this.getResources().getDrawable(R.drawable.eye_gray_1);origin1 = drawable1.getBitmap();BitmapDrawable drawable2 = (BitmapDrawable) this.getResources().getDrawable(R.drawable.eye_gray_2);origin2 = drawable2.getBitmap();}Paint paint = new Paint();paint.setAntiAlias(true);float scale = (float) origin1.getWidth() / (float) getWidth();int maxWidth = (int) (origin1.getWidth() / scale);int maxHeight = (int) (origin1.getHeight() / scale);int maskSize = 1;if (progress > 0.3f) {maskSize = (int) (maxHeight * (progress - 0.3) / 0.7);}Bitmap temp1 = Bitmap.createScaledBitmap(origin1, (int) (maxWidth),(int) (maxHeight), true);Canvas canvas = new Canvas();Bitmap mask = Bitmap.createBitmap(temp1.getWidth(), temp1.getWidth(),Config.ARGB_8888);canvas.setBitmap(mask);canvas.drawCircle(mask.getWidth() / 2, mask.getHeight() / 2, maskSize,mPaint);Bitmap bitmap = Bitmap.createBitmap(getWidth(), getHeight(),Config.ARGB_8888);canvas.setBitmap(bitmap);canvas.drawBitmap(temp1, (getWidth() - temp1.getWidth()) / 2,(getHeight() - temp1.getHeight()) / 2, paint);paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.DST_IN));canvas.drawBitmap(mask, (getWidth() - mask.getWidth()) / 2,(getHeight() - mask.getHeight()) / 2, paint);paint.setXfermode(null);float scaleProgress = progress / 0.3f;if (scaleProgress > 1.0f) {scaleProgress = 1.0f;}Bitmap temp2 = Bitmap.createScaledBitmap(origin2,(int) (maxWidth * scaleProgress),(int) (maxHeight * scaleProgress), true);Matrix matrix = new Matrix();matrix.postRotate(rotateProgress);temp2 = Bitmap.createBitmap(temp2, 0, 0, temp2.getWidth(),temp2.getHeight(), matrix, false);canvas.drawBitmap(temp2, (getWidth() - temp2.getWidth()) / 2,(getHeight() - temp2.getHeight()) / 2, paint);temp1.recycle();temp2.recycle();mask.recycle();return bitmap;}public void setProgress(float progress) {this.progress = progress;this.invalidate();}public void startAnimate() {if (!isAnimate) {isAnimate = true;// mHandler.post(mRunnable);} }public void stopAnimate() { isAnimate = false;// mHandler.removeCallbacks(mRunnable);rotateProgress = 0;}public Runnable mRunnable = new Runnable() {@Overridepublic void run() {// TODO Auto-generated method stubrotateProgress += 10;if (rotateProgress > 360) {rotateProgress = 0;}if (isAnimate) {mHandler.postDelayed(this, 10);}EyeView.this.invalidate();} };
}

再看下消息列表界面,监听Listview下拉的高度,来绘制EyeView,并打开视频录制界面。

package com.example.wechat01;import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.ListView;import com.example.wechat01.adpter.NewMsgAdpter;
import com.example.wechat01.widght.EyeView;
import com.example.wechat01.widght.PullDownListView;
import com.example.wechat01.widght.PullDownListView.OnPullHeightChangeListener;
import com.yixia.camera.demo.ui.record.MediaRecorderActivity;/*** 消息界面* * @author allenjuns@yahoo.com**/
public class Fragment_Msg extends Fragment {private Activity ctx;private View layout;private ListView listview;@Overridepublic View onCreateView(LayoutInflater inflater, ViewGroup container,Bundle savedInstanceState) {if (layout == null) {ctx = this.getActivity();layout = ctx.getLayoutInflater().inflate(R.layout.framen_msg, null);initView();initPullDownView();} else {ViewGroup parent = (ViewGroup) layout.getParent();if (parent != null) {parent.removeView(layout);}}return layout;}private void initView() {// TODO 实现本页面的布局 }private void initPullDownView() {final PullDownListView pullDownListView = (PullDownListView) layout.findViewById(R.id.pullDownListView);final EyeView eyeView = (EyeView) layout.findViewById(R.id.eyeView);pullDownListView.getListView().setAdapter(new NewMsgAdpter(getActivity()));pullDownListView.setOnPullHeightChangeListener(new OnPullHeightChangeListener() {@Overridepublic void onTopHeightChange(int headerHeight,int pullHeight) {// TODO Auto-generated method stubfloat progress = (float) pullHeight/ (float) headerHeight;if (progress < 0.5) {progress = 0.0f;} else {progress = (progress - 0.5f) / 0.5f;}if (progress > 1.0f) {progress = 1.0f;}if (!pullDownListView.isRefreshing()) {eyeView.setProgress(progress);}}@Overridepublic void onBottomHeightChange(int footerHeight,int pullHeight) {// TODO Auto-generated method stubfloat progress = (float) pullHeight/ (float) footerHeight;if (progress < 0.5) {progress = 0.0f;} else {progress = (progress - 0.5f) / 0.5f;} if (progress > 1.0f) {progress = 1.0f;} if (!pullDownListView.isRefreshing()) { } }@Overridepublic void onRefreshing(final boolean isTop) {// TODO Auto-generated method stubif (isTop) {eyeView.startAnimate();} else {// progressView.startAnimate();}// 打开视频录制页面Intent intent = new Intent(ctx,MediaRecorderActivity.class);ctx.startActivity(intent); ctx.overridePendingTransition(R.anim.push_up_in,R.anim.push_up_out);pullDownListView.pullUp();}});pullDownListView.getListView().setOnItemClickListener(new OnItemClickListener() {@Overridepublic void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3) {// TODO Auto-generated method stub } }); }
}

这个Demo比较复杂,具体实现方式请大家去Github研究一下代码吧~
另外还有视频录制这块的功能,有些复杂,这块是用的秒拍团队提供的视频录制SDK,感兴趣的可以去官网膜拜~

官网地址:

OK,项目的完整代码可以去 Github (点击这里) 下载。

本系列文章会教你一步步打造自己的高仿微信APP,尽请关注本博客!

【高仿微信系列】03、微信录制小视频相关推荐

  1. Android之---高仿微信录制小视频(拍摄和查看)

    高仿微信录制小视频(拍摄和查看) Android仿微信小视频录制功能 http://blog.csdn.net/u012227600/article/details/50835633 Android仿 ...

  2. android高仿微信小视频,Android仿微信录制小视频

    本文实例为大家分享了Android仿微信录制小视频的具体代码,供大家参考,具体内容如下 先上张图片看看效果 简单叙述下 首先通过Camera类调用系统相机 通过surfaceview绘制出来 通过Me ...

  3. 仿微信的录制小视频功能

    仿微信的录制小视频功能 这里主要重点介绍录制的过程和录制完播放的过程,其次会简单介绍一下录制按钮的实现. 总纲简介 首先我们录制视频需要知道用到几个类 SurfaceView Camera Media ...

  4. Android录制小视频(仿微信小视频)

    Android录制小视频 一.概述 日常生活中,录制一些视频已经渐渐成为一种习惯,当然这对于我们技术来说并没有什么影响,因为无论大家用不用,你都需要开发,这只是需求制定者–PM应该关心的事情,我们需要 ...

  5. android录制视频计时,Android实现微信录制小视频的计时动画

    使用微信录制小视频时会有一个倒计时的横线,如下图: 这个横线怎么实现呢? 尝试了以下几种方法: ProgressBar 自定义View + 定时器 + 重绘 TextView动态改变宽度 第一种方式使 ...

  6. Android模仿微信录制小视频

    模仿微信录制小视频 使用系统MediaRecorder进行录制 效果预览: 预览apk下载:https://fir.im/sd36 github源代码:https://github.com/yuanf ...

  7. 谈谈微信首页下拉拍摄小视频功能

    时间回到2014年,此刻你就是一名光荣的微信产品经理,在此前一年Twitter旗下短视频分享应用Vine已经风靡了美国,而国内以美拍为代表的国内学徒也是搅得风声水起.此刻核心功能为移动即时通讯的微信, ...

  8. 高仿QQ的手机管家的小火箭加速

    高仿QQ的手机管家的小火箭加速 1.前言 腾讯的手机管家,用过这个App的人都应该知道桌面的火箭一键加速这个功能,研究一下这个小火箭是怎么做出来的.先来了解一下小火箭有神马动作,首先在没有触碰它时,就 ...

  9. HTML高仿哔哩哔哩(B站)视频网站整站模板

    简介: 100%高仿哔哩哔哩(B站)视频网站模板,包含首页.列表和内容页整站模板. 网盘下载地址: http://kekewangLuo.net/D94pktwZmYc0 图片:

最新文章

  1. 2022-2028年中国塑料绳的制造行业市场现状调查及投资商机预测报告
  2. Unity中使用射线查询MeshCollider背面的方法
  3. 5g局域网传输速度_这个路由太牛了吧?,三步搭建局域网,接上U盘就是NAS
  4. Java排序算法之——希尔排序
  5. [C#-SQLite] SQLite一些奇怪的问题
  6. occam‘s razor
  7. Token Bucket原理
  8. 分布式网络游戏百万人同时在线服务器架构实现
  9. pg库sharelock_PostgreSQL LOCK(锁)
  10. 如何在yml中加上git用户名和密码的验证_使用Apollo升级一下yml文件管理和发布
  11. BZOJ3711 PA2014Druzyny(动态规划+cdq分治+线段树)
  12. zeppelin 连接hive 认证方式_HIVE的学习之路(六)Hive的分组Join排序
  13. linux下跑分软件下载,geekbench5下载-多平台综合性测试工具 v5.3.1 免费版 - 下载吧...
  14. 无线路由器和无线网卡的普及知识贴及选择(2019.05更新802.11AX网卡,3T3R wave2路由器推荐)
  15. 手写一个识别旺旺/千牛,手机在线/电脑在线状态的小工具
  16. WSO2 Micro Integrator环境安装及部署
  17. python 打开txt文件
  18. 微信小程序豆瓣电影(上)
  19. 关于c++产生string subscript out of range问题的自己的经历与解决方案
  20. 2016年上半年光伏企业沉浮录

热门文章

  1. 强烈推荐一波高质量的公众号,全是圈内大佬!
  2. 多测师_Python 介绍
  3. c++输入/输出 i/o_C基本输入/输出-能力问题与解答
  4. docker服务重启后自动重启容器
  5. krusal算法无解析(周灵猪)
  6. unity 光照烘焙效果很虚的问题
  7. SAP MM 为UB类型的STO执行VL10B,报错-没有项目类别表存在(表T184L NL 0002 V)-之对策
  8. 武汉ISO20000体系认证服务流程为什么如此重要?
  9. 第2章基本结构:集合、函数、序列、求和与矩阵
  10. 传感器实验——485噪声模块