猴年猴赛雷啊各位,今天没吃药我感觉自己萌萌哒!

qq和微信和支付宝红包大战,不知道各位的战绩是多少嘞? 反正我qq抢到的都是气泡。因为太不爽,所以自己写一个下拉抢红包自己玩(自己跟自己玩)。

先来看效果图。这个…… 呃~~ -__-” 。。有点丑 是低仿。

转载请注明出处:http://blog.csdn.net/wingichoy/article/details/50662592

学习完本篇博客你能获得到的知识

  1. 正确的获得view的大小
  2. listview的下拉header
  3. 自定义字体
  4. 自己添加监听器

废话不多说,快跟我来一起动手

  • 首先来跟我打造一个自定义的listview

新建一个类,继承自listview,这里需要来重写一下他的overScrollBy()方法。

public class HBListView extends ListView {

    //header显示的图片
private MyImageView mImageView;
private Context mContext;
//抢到红包时候的监听器
private OnSuccessListener mOnSuccessListener; @Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
Log.e("wing", "deltaY:" + deltaY + " scrollY:" + scrollY);
return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); }

先来介绍一下重要参数的意思

deltaX,Y是指速度值,也就是你手指滑动的瞬时速度。

scrollX,Y 水平和数值方向上的变化量

isTouchEvent 表示手指是否在触摸状态

观察log可以轻易看到他们与手机触摸的关系。大家自己试验一下就可以。

接着给listview加一个header

mListView = (HBListView) findViewById(R.id.lv);

        final View header = LayoutInflater.from(this).inflate(R.layout.view_header,null);
mListView.addHeaderView(header);

其实这个header就是个图片。 我们刚才从listview的监听上面看到了偏移量。所以可以根据偏移量来动态改变图片的大小。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"> <com.wingsofts.hongbao.MyImageView
android:id = "@+id/imageView"
android:scaleType="centerCrop"
android:layout_width="match_parent"
android:layout_height="0dp"
android:src="@drawable/bg" />
</LinearLayout>

因为header刚开始是隐藏的,所以这里高度设置为0.

这里来一个小插曲。。不知道大家有没有在activity中获取view的高度呢。是不是有时候只能拿到0。对于这个问题呢。正确的获取view宽高有如下几种解决方案。

1.onWindowsFocusChanged()

2.view.postRunnable() 将一个runnable投递到消息队列尾部。

3.ViewTreeObserver

这里采用第三种方法,在OnGlobalLayoutListener中 调用listview的changSize方法。。

header.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
mListView.changeSize(image);
header.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
});

这里看看listview的changsize方法,其实只是将header的引用传来而已..这是因为之前在这里获取高度,后来又去掉了。。偷懒没有改方法名

   public void changeSize(MyImageView imageView) {
mImageView = imageView;
}

拿到了图片之后,理所当然是根据手指来改变图片的大小啦。 还记得onScrollBy里面的几个参数吗,我们只需要在 (触摸的时候&&下滑的时候) 改变图片的大小就可以了。

下滑的状态可以根据log得知为deltaY<0.

 @Override
protected boolean overScrollBy(int deltaX, int deltaY, int scrollX, int scrollY, int scrollRangeX, int scrollRangeY, int maxOverScrollX, int maxOverScrollY, boolean isTouchEvent) {
Log.e("wing", "deltaY:" + deltaY + " scrollY:" + scrollY); //给图片一个最大值
if (mImageView.getHeight() < 300) {
//是触摸状态 以及 是下滑状态
if (isTouchEvent && deltaY < 0) {
//动态改变imageView的大小
mImageView.getLayoutParams().height += Math.abs(deltaY);
mImageView.requestLayout();
}
} return super.overScrollBy(deltaX, deltaY, scrollX, scrollY, scrollRangeX, scrollRangeY, maxOverScrollX, maxOverScrollY, isTouchEvent); }

这样便可以下拉了,现在的效果是这样的。

咦。。是可以下拉了。但是没有回弹,怎么办!

还能怎么办 写一个就是了。思路就是用一个动画,来不停地改变header高度。

ObjectAnimator的使用

他的使用方法很简单,他通过反射调用set方法来改变view的属性然后发生动画。这里直接上例子,首先重写一下imageview,添加一个setHeight()方法.

public class MyImageView extends ImageView {
private Paint mPaint;
public void setHeight(int height) { getLayoutParams().height = height;
requestLayout();
}
}

然后在使用ObjectAnimator的ofInt方法,获取到一个ObjectAnimator,这里ofXXX具体看参数类型。

//获取mImageView的setHeight方法,数值从当前图片的高度逐渐到0,产生动画
private void closeHeader() {
ObjectAnimator oa = ObjectAnimator.ofInt(mImageView, "height", mImageView.getHeight(), 0);
oa.start();
}

这时候关闭动画就做完啦。想要关闭的时候 只需要在action_up调用closeHeader()方法即可.现在是这样的:

 @Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP:
closeHeader();
break;
}

咦,有没有似曾相识的赶脚,没错!!这特么的不就是下拉刷新么。 好了本篇博客到此结束!!

额。。你先把手里的刀放下w(゚Д゚)w!!!

刚才结束的是下拉刷新的博客,现在继续写抢红包的博客。。。

思路就是用一个变量来保存连刷的次数,再用随机数判断是否抽中红包。

给MyImageView一个public的属性次数

public class MyImageView extends ImageView {
public int mTime;
}

然后只要在ACTION_UP的时候,判断随机数有没有抽中,决定次数是否累加:

   @Override
public boolean onTouchEvent(MotionEvent ev) {
switch (ev.getAction()) {
case MotionEvent.ACTION_UP: int ran = (int) (Math.random() * 10);
//设置中奖概率
if (ran > 1) {
//如果没中次数累加
mImageView.mTime++;
closeHeader();
} else {
//否则为中奖
mImageView.mTime = 0;
if (mOnSuccessListener != null) {
mOnSuccessListener.onSuccess();
}
closeHeader();
} break;
} return super.onTouchEvent(ev);
}

逻辑是不是粉简单! 聪明的你已经看到了抢红包成功的回调。这个等等说,先说拿到了次数以后怎么做。

拿到了次数之后理所应道就是把文字画上去啦~~ 这里为了方便就给了一个固定的位置。因为数字大小跟文字不一样,所以把字符串分了三串来画..

  public int mTime;
private Typeface mTypeFace;
private float mTxtHLength;
private float mTxtRLength; private String txtH = "连刷";
private String txtR = "次,加油!"; public MyImageView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
mPaint = new Paint();
mPaint.setColor(Color.YELLOW);
mMidPaint = new Paint();
mMidPaint.setColor(Color.YELLOW);
mTypeFace = Typeface.createFromAsset(context.getAssets(), "ifont.ttf");
mMidPaint.setTypeface(mTypeFace);
mPaint.setTypeface(mTypeFace);
//设置文字大小
mPaint.setTextSize(50);
//设置数字大小
mMidPaint.setTextSize(100); //测量头文字的长度
mTxtHLength = mPaint.measureText(txtH);
//测量尾文字的长度
mTxtRLength = mPaint.measureText(txtR);
}
@Override
protected void onDraw(Canvas canvas) { super.onDraw(canvas);
String count = mTime + "";
//数字的长度
float countLength = mMidPaint.measureText(count);
//总体长度
float totalLength = mTxtRLength + countLength; //画在正中间
float start = getMeasuredWidth() / 2 - totalLength / 2; canvas.drawText(txtH, 100, getMeasuredHeight() / 2, mPaint);
canvas.drawText(count, start + countLength / 2, getMeasuredHeight() / 2, mMidPaint);
canvas.drawText(txtR, start + countLength / 2 + mTxtRLength / 2, getMeasuredHeight() / 2, mPaint);
}

这样就把次数提示画上去了!来看看效果:



这个…… 呃~~ -__-” 是画上去了,但是

字!体!好!丑!

没事没事,别着急。。我们换一个字体就是了。

Paint字体的改变

1.首先下载一个字体 放到assets文件夹下

2.获取到字体的引用

3.给画笔设置字体

        //改变字体,就是这么轻松自如~~
mTypeFace = Typeface.createFromAsset(context.getAssets(), "ifont.ttf");
mMidPaint.setTypeface(mTypeFace);
mPaint.setTypeface(mTypeFace);

看效果图:

吼吼吼~~~ 有点感觉了。

监听器的添加

先来回过头来,大家知道View有setOnClickListener.. 那么我们也来加一个红包成功监听器吧。

在ListView里面增加一个内部接口,添加一个set方法


private OnSuccessListener mOnSuccessListener; interface OnSuccessListener {
void onSuccess();
} public void setOnSuccessListener(OnSuccessListener onSuccessListener) {
mOnSuccessListener = onSuccessListener;
}

在ACTION_UP成果逻辑里面调用onSuccess()… 这就是监听器。。简单吧~就是个回调

现在在MainActivity里使用这个抢红包listView吧~

设置一个监听器,里面写你想要的事件,中几千万的随便写,总比气泡好,,

 mListView.setAdapter(new ArrayAdapter(this,android.R.layout.simple_list_item_1,datas));
mListView.setOnSuccessListener(new HBListView.OnSuccessListener() {
@Override
public void onSuccess() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("恭喜中奖!抽到了疼逊聊天气泡!").setNegativeButton("确认", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) { }
}).show();
}
});

这样就能出现文章顶部预览图的效果了:

如果你喜欢我的博客,请继续关注我,求赞求顶~求吐槽

本项目地址:打开链接

———————————–华丽丽的分割线————————————

效果优化

处于追求完美的心态,群友 小情歌 对代码做了一些优化,主要有

1.修复上滑也显示红包的bug

2.优化动画事件,在松手的过程中如果继续ACTION_DOWN则放弃动画

3.增加视差特效

修改其实也不复杂 具体看这一段代码:

 @Override
public boolean onTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_DOWN:
x1 = ev.getX();
y1 = ev.getY(); if (oa != null) {
if (oa.isRunning()) {
oa.cancel();
}
} if (mImageView.getHeight() == 0) {
mImageView.mTime = 0;
}
break; case MotionEvent.ACTION_CANCEL:
case MotionEvent.ACTION_UP: x2 = ev.getX();
y2 = ev.getY();
if (y1 - y2 > 0) {
b = false;
} else if (y2 - y1 > 0) {
b = true;
} int ran = (int) (Math.random() * 100);
Log.e("wing", ran + "");
if (b) { //往下滑 if (ran > 3) {
mImageView.mTime++;
closeHeader();
} else {
mImageView.mTime = 0;
if (mOnSuccessListener != null) {
mOnSuccessListener.onSuccess();
}
closeHeader();
}
} break;
}
return super.onTouchEvent(ev);
}

相信大家都看得懂,这里就不一一说明了。

恭喜发财! -- 手把手教你仿造一个qq下拉抢红包 Android自定义view的更多相关文章

  1. 手把手教你实现RecyclerView的下拉刷新和上拉加载更多

    手把手教你实现RecyclerView的下拉刷新和上拉加载更多     版权声明:本文为博主原创文章,遵循CC 4.0 by-sa版权协议,转载请附上原文出处链接和本声明. 本文链接:https:// ...

  2. 手把手教你轻松实现listview下拉刷新

    很多人觉得自定义一个listview下拉刷新上拉加载更多是一件很牛x的事情,不是大神写不出来,我想大多数童鞋都是做项目用到时就百度,什么pulltorefresh,xlistview...也不看原理, ...

  3. android新闻项目、饮食助手、下拉刷新、自定义View进度条、ReactNative阅读器等源码

    Android精选源码 Android仿照36Kr官方新闻项目课程源码 一个优雅美观的下拉刷新布局,众多样式可选 安卓版本的VegaScroll滚动布局 android物流详情的弹框 健身饮食记录助手 ...

  4. 只有20行Javascript代码!手把手教你写一个页面模板引擎

    http://www.toobug.net/article/how_to_design_front_end_template_engine.html http://barretlee.com/webs ...

  5. iOS回顾笔记(05) -- 手把手教你封装一个广告轮播图框架

    html,body,div,span,applet,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,bi ...

  6. PWA入门:手把手教你制作一个PWA应用

    摘要: PWA图文教程 原文:PWA入门:手把手教你制作一个PWA应用 作者:MudOnTire Fundebug经授权转载,版权归原作者所有. 简介 Web前端的同学是否想过学习app开发,以弥补自 ...

  7. R数据分析:跟随top期刊手把手教你做一个临床预测模型

    临床预测模型也是大家比较感兴趣的,今天就带着大家看一篇临床预测模型的文章,并且用一个例子给大家过一遍做法. 这篇文章来自护理领域顶级期刊的文章,文章名在下面 Ballesta-Castillejos ...

  8. 手把手教你画一个 逼格满满圆形水波纹loadingview Android

    才没有完结呢o( ̄︶ ̄)n .大家好,这里是番外篇. 拜读了爱哥的博客,又学到不少东西.爱哥曾经说过: 要站在巨人的丁丁上. 那么今天,我们就站在爱哥的丁丁上来学习制作一款自定义view(开个玩笑,爱 ...

  9. 手把手带你做一个超炫酷loading成功动画view Android自定义view

    写在前面: 本篇可能是手把手自定义view系列最后一篇了,实际上我也是一周前才开始真正接触自定义view,通过这一周的练习,基本上已经熟练自定义view,能够应对一般的view需要,那么就以本篇来结尾 ...

随机推荐

  1. Node.js 教程

    简单的说 Node.js 就是运行在服务端的 JavaScript. Node.js 是一个基于Chrome JavaScript 运行时建立的一个平台. Node.js是一个事件驱动I/O服务端Ja ...

  2. Docker 控制组

    控制组(cgroups)是 Linux 内核的一个特性,主要用来对共享资源进行隔离.限制.审计等.只有能控制分配到容器的资源,才能避免当多个容器同时运行时的对系统资源的竞争. 控制组技术最早是由 Go ...

  3. 潜谈IT从业人员在传统IT和互联网之间的择业问题(上)-传统乙方形公司

    外包能去吗?项目型公司如何?甲方比乙方好?互联网公司就一定好吗? 相信许多从业者在经历了3-5年的工作期后都会带着这样的疑问或者疑惑. 2012年-2014年间,曾经面试过500人,亲身面试的也有15 ...

  4. Android开发技巧——定制仿微信图片裁剪控件

    拍照--裁剪,或者是选择图片--裁剪,是我们设置头像或上传图片时经常需要的一组操作.上篇讲了Camera的使用,这篇讲一下我对图片裁剪的实现. 背景 下面的需求都来自产品. 裁剪图片要像微信那样,拖动 ...

  5. Swift按照数组元素出现的次数及大小排序

    要求如下: 1.已知一个数组,按照单个元素在数组中出现的次数作为重新排序的依据,个数多的排在前面 2.相同个数时候,元素值大的排前面 例子: [1, 2, 2, 3, 5, 5] 经过计算得到的结果是 ...

  6. FORM实现中打开图片,链接,文档(参考自itpub上一篇帖子,整理而来)

    FORM实现中打开图片,链接,文档 参考自itpub上一篇帖子,整理而来 1.添加PL程序库D2kwutil.pll 2.主要实现程序 /*过程参数说明: v_application --打开文件的应 ...

  7. cassandra eclipse 环境构建

    摘要 本文主要介绍如何在eclipse中搭建cassandra环境 更多cassandra,nosql 相关知识请访问http://www.webpersonaldeveloper.cn 正文 1.f ...

  8. JDOM生成、解析XML实例

    import java.io.File; import java.io.FileNotFoundException; import java.io.FileOutputStream; import j ...

  9. XMPP系列(六)---创建群组

    最近公司项目需要,要做一个自己的IMSDK,顺便先把之前没有记录的群聊功能记录一下. 先上资料,查看XMPP群聊相关的资料,可以去这里看协议:XEP-0045 . 创建群组 XMPP 框架里有一个类X ...

  10. Android View的绘制过程

    首先是view的绘制过程~最主要的分三部分 measure layout draw 看字面意思,计算,布局,画~ android中控件相当于是画在一个无限大的画布上的,那就产生了几个问题 画布无限大, ...