自定义博客皮肤VIP专享

*博客头图:

格式为PNG、JPG,宽度*高度大于1920*100像素,不超过2MB,主视觉建议放在右侧,请参照线上博客头图

请上传大于1920*100像素的图片!

博客底图:

图片格式为PNG、JPG,不超过1MB,可上下左右平铺至整个背景

栏目图:

图片格式为PNG、JPG,图片宽度*高度为300*38像素,不超过0.5MB

主标题颜色:

RGB颜色,例如:#AFAFAF

Hover:

RGB颜色,例如:#AFAFAF

副标题颜色:

RGB颜色,例如:#AFAFAF

自定义博客皮肤

-+
  • 博客(19)
  • 资源 (17)
  • 收藏
  • 关注

原创 坊间传言:程序员可以先在大厂镀金,以后去中小厂毫无压力,基本不会被卡,事实果真如此吗?

近日,一个大厂程序员发帖抱怨:谁说的大厂镀金?信了你们的鬼话,从大厂裸辞两个多月,一个offer都没拿到。早知道前几年就选虾皮了,给的钱还多八万。楼主总结了自己今年的面试情况:虾皮一面挂,阿里二面挂,字节一面挂,微众二面挂,货拉拉二面挂,简直无语!楼主自爆,自己是985硕,今年快29岁了,之前在深圳鹅厂工作。网友感叹:现在的互联网这么卷了吗?985硕,腾讯的履历,随便拿个offer应该很容易吧?也有许多网友不赞成楼主裸辞的行为,有人觉得不可思议,在深圳竟然敢裸辞?有人觉得裸辞太伤,尽量不要

2021-06-30 14:05:15 620 4

转载 Android 开发技术——从 LiveData 迁移到 Kotlin 数据流

好文推荐:作者:Android_开发者LiveData 的历史要追溯到 2017 年。彼时,观察者模式有效简化了开发,但诸如 RxJava 一类的库对新手而言有些太过复杂。为此,架构组件团队打造了 LiveData: 一个专用于 Android 的具备自主生命周期感知能力的可观察的数据存储器类。LiveData 被有意简化设计,这使得开发者很容易上手;而对于较为复杂的交互数据流场景,建议您使用 RxJava,这样两者结合的优势就发挥出来了。DeadData?LiveData 对于 Java 开发.

2021-06-29 17:05:33 469

原创 应届学妹竟一次性通过美团Android 岗四面,瞬间感觉自己太菜了!

学妹自述:美团,是在boss上投的简历,之前也投过一次,简历都没通过删选,后来让同学帮忙改了一下简历,重新投另一个部门,获得了面试机会。5月3日,中午HR打电话过来预约了下午4点半面试,说会在线写代码,让我准备好网络环境。结果5点半还没打电话过来,被放鸽子。与hr重新沟通过后,确定周下一下午再面,可是跟hr沟通预约这一套貌似在美团并没有什么用。不过羡慕归羡慕,不过这又为我码字提供了素材(哈哈哈),咱今天就大致分享一下学妹的这美团 Android 4面面经,看看人家大厂面试都问了些啥?美团 An.

2021-06-28 18:01:21 434 1

原创 Jetpack Compose和View的互操作性

Jetpack Compose InteroperabilityCompose风这么大, 对于已有项目使用新技术, 难免会担心兼容性. 对于Compose来说, 至少和View的结合是无缝的. (目前来讲, 已有项目要采用Compose, 可能初期要解决的就是升级gradle plugin, gradle, Android Studio, kotlin之类的问题.)构建UI的灵活性还是有保证的:新界面想用Compose, 可以.Compose支持不了的, 用View.已有界面不想动, 可以不动.

2021-06-27 21:46:12 1989 3

原创 闲聊 Android Framework 核心技术

今天,想跟大家聊聊,Framework开发的那些事。系统应用开发,现在来说,已经开始脱离系统,单独拿出来开发,系统定制接口,已提供给应用调用,用来增强功能。原生的桌面,拨号,设置,已经没法做出差异化优势,因此都费尽心机,来进行应用深度开发。对于之前维护系统应用模块的人来讲,修修补补,真的没有什么成长。每天的工作来说,没有很深的技术壁垒,很容易被别人攻陷。比如设置,比如联系人,在小的改动,修改故障的时候,没有非常高的要求,做过应用开发的,都可以过来参合一脚,改改问题。而让一个应用开发得去修改系统接口.

2021-06-25 17:10:47 448 3

JetPack为什么让Android开发又爱又恨?

Android发展至今已经有很多年头了,但是有一个问题是一直萦绕在每一个Android开发者以及Google心中的,那就是Android的碎片化。一个应用从立项到上线,要经历很多的步骤,但是对于开发人员来说,有一个很头大的事情,就是解决Android市场碎片化的问题,各个Android版本的测试,各个Android手机的测试等等,这都是因为Android没有标准。终于,随着JetPack的面世,让Android开发人员看到了一丝希望,看到了Google的决心。从JetPack的发布,到Android官网

2021-06-24 13:54:50 259

转载 APP路由框架与组件化简析

作者:看书的小蜗牛在Android APP开发中,路由还经常和组件化开发强关联在一起,那么到底什么是路由,一个路由框架到底应该具备什么功能,实现原理是什么样的?路由是否是APP的强需求呢?与组件化到底什么关系,本文就简单分析下如上几个问题。路由的概念路由这个词本身应该是互联网协议中的一个词,维基百科对此的解释如下:路由(routing)就是通过互联的网络把信息从源地址传输到目的地址的活动。路由发生在OSI网络参考模型中的第三层即网络层。个人理解,在前端开发中,路由就是通过一串字符串映射到对应.

2021-06-18 21:58:14 369 2

原创 二流程序员逆袭字节跳动Android开发岗,薪资涨了40%多

作者:赵无极前言首先说一下,笔者曾经也只是尘世间一个迷途小开发,二流程序员。可能这篇文章并不像其他面经一样金光闪闪,只是一个二流Android攻城狮在市场的大潮之下,耗时一个月时间面试+复习+总结,最终拿到了自己喜欢公司offer(字节跳动Android开发岗,薪资也涨了40%多),对我来说已经很满意了。出来社会摸爬滚打四年多,不得不承认人是分三六九等的。即便是专注度、努力这些颇为客观的因素,也是因人而异的。说下我的个人背景吧:双非本科,计算机应用专业。工作四年,都是小厂,小组最多没超过.

2021-06-18 17:51:25 408 4

转载 一篇通俗易懂的Android视图系统设计与实现

好文推荐作者:Bezier前言说到Android视图大家第一反应肯定是Activity以及View,毕竟这是我们从入门开始接触最多的两个组件。但提到Activity和View之间联系以及设计背景可能会难道一大片人。其实关于视图系统还有一个重要概念Window不那么经常被提起,Android的设计者为了让开发者更容易上手,基于迪米特法则将Window屏蔽在内部。本文将从设计背景为出发点阐述Activity、Window、View的实现流程,帮你换一种角度看Android视图系统,相信读完会让你耳目.

2021-06-17 21:48:03 324 3

原创 抱紧风口技术潮流!开启Android开发的新篇章!

目前市场中使用音视频技术的公司太多了,大到全民观看短视频,小到直播带货,大家平均在手机上消耗的时间也越来越多。总的来说,国内的音视频行业可以划分为三类:第一类:短视频抖音、快手、微视等短视频平台大量使用音视频技术,主要以视频内容为主,对视频压缩性要求高,尽可能做到视频文件小的同时,保证清晰度高。第二类:直播带货京东、淘宝;斗鱼、虎牙等将直播带到大家面前,前者以直播带货为主,后者以直播消费为主,对技术的要求做到:直播秒开、延时性低、在弱网环境下也能保证正常收看直播。第三类:即

2021-06-17 17:21:11 258 5

原创 最近,又有人在“ 唱衰 “ Android 的发展前景了

抱怨年年有,今年特别多最近不断地也听见很多人在谈做Android是否还有前途?Android研发是不是在走下坡路了?今年Android的工作是不是特别难找了?…这些话题首先我在这里先表明我自己的观点,我是持否定态度的,并且我有很多的话想对你们说;一.关于Android的前景对于这些其实我的看法很简单,现在真的还没到说Android开发已经无路可走的地步,当然未来怎样我无法预判。现在各大公司其实都很缺Android研发(中高级),不断的在招人,就拿很多一线互联网来说,别说来面试的人了,就简历都拿不

2021-06-16 21:39:25 291 2

原创 Activity布局流程+资源加载过程+插件化换肤思路

Activity布局流程Activity框架1.Activity里有一个window,在初始化的时候是空的,然后在activity.attach()里赋值为PhoneWindow2.PhoneWindow里有一个DecorView,这个DecorView就是一个FrameLayout,是整个Activity的根布局3.当新建Activity时选择不同的主题会有不同的根布局4.比如选择的是空白的Activity,那就是分为两部分ViewStub预留和FrameLayout 这个FrameLayout

2021-06-16 18:00:23 555 3

原创 一款零侵入的高效Flutter混合栈管理方案,你值得拥有!

在实际的工作场景中,我们很难从零开始用纯Flutter去建设一个项目,也正是因为这样,Native+Flutter混合栈跳转管理使我们在混合开发的时候不得不首先考虑的问题,因为我们很难保证不会遇到下面的情况。那么如何做技术选型困惑了不少想要做混开的同学,毕竟Flutter的生态还不是十分成熟,现成的解决方案和轮子并不多,而且还不一定好用,要么资源占用过高,要么侵入性太强。好在经过这几天的摸索,总结出来了一套方案,供大家学习参考,相互交流。按照国际惯例,我先介绍一下目前市场上的一些解决方案以及存在的问

2021-06-15 21:42:13 12081 14

原创 什么是Handler的同步屏障机制?

前言对于Handler机制,想必大家都已经非常熟悉了吧,从迈进Android开发这扇大门的时候,就不停的研究和使用它,同样的这也是Android系统架构的精髓之一。然而在我们使用的时候,往往会忽略掉一些不常见却又很重要的内容,今天就来讲一讲经常被忽略的同步屏障以及异步消息。制流程中窥视handler同步屏障为了引出今天的主题,我们先来看看ui的渲染流程吧。在Android的绘制流程中,ViewRootImpl这个类发挥了非常重要的作用,首先我们看一下这个类中比较重要的一个方法requestLayou.

2021-06-10 15:17:11 1959 4

转载 华为 HarmonyOS 的野心比你想象中更大

在宗教艺术中,我们常常能看到一座中途停工的高塔。它被称作「巴别塔」。宗教故事里,巴别塔是人类联合而造,希望能够通向天堂的高塔。但上帝为了阻止人类这一计划,让人类不再说统一的语言,致使相互间无法沟通。因此巴别塔计划只好作罢。语言的隔阂,阻碍了人类的合作。该故事后来也多被寓意语言、沟通的重要性。实际上,智能设备也有自己的语言。比如手机的语言可能是 Android、iOS,电脑的语言可能是 Windows、macOS,电视的语言可能是 tvOS、GoogleTV…… 使用不同「语言」的设备,在联接、协作时

2021-06-08 17:06:42 357

原创 Jetpack 组件之 Lifecycle 使用与浅析

Lifecycle 是什么?官方解释:Lifecycle is a class that holds the information about the lifecycle state of a component (like an activity or a fragment) and allows other objects to observe this state.个人理解: Lifecycle 就是管理组件( Activity / Fragment )生命周期的一个工具(类),可以在其他

2021-06-06 21:54:13 238

转载 屏幕刷新与View之间的你依我侬

好文推荐:作者:RugerMcrequestLayout与invalidate众所周知,View三大流程是Measure、Layout、Draw,在SDK中我们在View中只能找到 requestLayout (包括Measure与Layout)与 invalidate (包括Draw)这两个方法。合并Measure与Layout是可以理解的,既然当View尺寸发生变化时说必然需要重新Measure和Layout的,这两个流程其实是密不可分的。可以看出仅需分析这两个方法就足以覆盖View三大流程,.

2021-06-04 21:44:52 274 2

转载 Flutter UI自动化测试技术方案选型与探索

作者:闲鱼技术——小匠Flutter页面无法直接使用Native测试工具定位元素,给自动化测试带来很多不便。虽然Google官方推出了Flutter driver 和 Integration test,但是在实际使用中存在以下问题:•不适用于混合栈APP,虽然appium中有相关的driver,但是无法切换环境。•元素定位能力相对薄弱。•依赖于VMService,需要构建Profile或Debug包。基于以上因素,我们并没有直接使用Google官方推出的工具,而是选择基于Native测试工具去扩展.

2021-06-03 22:18:10 640 2

原创 Android 进阶之探索 OkHttp 原理

前言1. OkHttp 请求处理流程概述当我们发起同步请求时,请求会被 Dispatcher 放到同步请求队列中,然后直接执行请求。当我们发起异步请求时,Dispatcher 会把请求放到异步请求队列,然后在合适的时机把异步请求提交到线程池中执行。请求的执行由拦截器链负责,处理的顺序为:重试与重定向拦截器—首部构建拦截器—缓存拦截器—连接拦截器—数据交换拦截器。当数据交换拦截器 CallServerInterceptor 接收到请求时,会通过数据交换器 Exchange 写入请求信息,而 Exc

2021-06-01 21:08:19 1100 1

组件化通信之LiveData.rar

都说新项目组件通信一定用LiveData,我们就从源码层来聊聊LiveData的魅力 内容点: 1.LiveData到底是什么? 2.LiveData源码解读? 3.通过手写LiveData让大家了解更清晰 4.如何将LiveData封装得更加好用?

2020-12-18

resized_img.zip

手势识别图片,主要是训练神经网络图片。用tersorflow实现手势识别

2019-07-12

WangyiPush.zip

直播详解,可运行,通过rtmp协议实现,直播的详细说明可参考https://github.com/interviewandroid/AndroidInterView/blob/master/android/live.md 关于直播的视频讲解可以加qq 1051917835 免费的 哦

2019-06-22

RabbitMQ消息中间件技术精讲

RabbitMQ消息中间件技术精讲(渐进式,深入RabbitMQ高级特性,手把手,整合RabbitMQ&Spring;家族,高可靠,构建RabbitMQ集群架构,追前沿,领略SET化架构衍化与设计)

2019-02-24

MySQL原理分析与架构设计视频教程

MySQL原理分析与架构设计(数据库索引优化,数据库的分库分表, SQL查询优化,mysql行内锁原理)

2019-02-24

2019Java高级面试专题

2019Java高级面试专题包含(微服务+数据库原理+Java性能优化面试视频)

2019-02-24

rxjava 1.0.14

rxjavah和rxandroid下载

2016-11-23

eclipse svn插件

2016-08-12

jbox2d愤怒的小鸟游戏源码

jbox2d愤怒的小鸟游戏源码

2016-07-14

FreScon源码下载

FreScon源码下载

2016-06-30

sdk build-tool 19.1.0

build-tool 19.1.0 解压到sdk下面的build-tools目录就可以了

2016-01-07

Xcode6.4 beta2 下载

Xcode6.4 ios版 适合mac 10.10以下版本

2015-12-27

cdt插件下载

Eclipse 中CDT插件 将文件解压后 分别放到对应的eclipse目录中的features 和plugins文件夹中

2015-12-27

城市选择器

城市选择器,自动定位,城市列表自动按拼音排序

2015-10-21

可以拨动的时间选择器

直接可以运行。漂亮的时间选择空间 public class MainActivity extends FragmentActivity implements OnDateSetListener, TimePickerDialog.OnTimeSetListener { public static final String DATEPICKER_TAG = "datepicker"; public static final String TIMEPICKER_TAG = "timepicker"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); final Calendar calendar = Calendar.getInstance(); final DatePickerDialog datePickerDialog = DatePickerDialog.newInstance(this, calendar.get(Calendar.YEAR), calendar.get(Calendar.MONTH), calendar.get(Calendar.DAY_OF_MONTH), isVibrate()); final TimePickerDialog timePickerDialog = TimePickerDialog.newInstance(this, calendar.get(Calendar.HOUR_OF_DAY) ,calendar.get(Calendar.MINUTE), false, false); findViewById(R.id.dateButton).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { datePickerDialog.setVibrate(isVibrate()); datePickerDialog.setYearRange(1985, 2028); datePickerDialog.setCloseOnSingleTapDay(isCloseOnSingleTapDay()); datePickerDialog.show(getSupportFragmentManager(), DATEPICKER_TAG); } }); findViewById(R.id.timeButton).setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { timePickerDialog.setVibrate(isVibrate()); timePickerDialog.setCloseOnSingleTapMinute(isCloseOnSingleTapMinute()); timePickerDialog.show(getSupportFragmentManager(), TIMEPICKER_TAG); } }); if (savedInstanceState != null) { DatePickerDialog dpd = (DatePickerDialog) getSupportFragmentManager().findFragmentByTag(DATEPICKER_TAG); if (dpd != null) { dpd.setOnDateSetListener(this); } TimePickerDialog tpd = (TimePi

2015-10-21

annotations注解

android annotations注解 快速注解,findbyid

2015-10-21

仿QQ自定义ListView 下拉刷新

package me.maxwin; import java.util.ArrayList; import me.maxwin.view.XListView; import me.maxwin.view.XListView.IXListViewListener; import me.maxwin.view.XListView.RemoveListener; import android.app.Activity; import android.content.Context; import android.content.Intent; import android.os.Bundle; import android.os.Handler; import android.view.View; import android.widget.AdapterView; import android.widget.AdapterView.OnItemClickListener; public class XListViewActivity extends Activity implements IXListViewListener ,RemoveListener,OnItemClickListener{ private XListView mListView; // private ArrayAdapter<String> mAdapter; private ItemAdapter adapter; // private Context context; private ArrayList<String> items = new ArrayList<String>(); private Handler mHandler; private int start = 0; private static int refreshCnt = 0; /** Called when the activity is first created. */ @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); geneItems(); init(); mHandler = new Handler(); } private void init() { // TODO Auto-generated method stub mListView = (XListView) findViewById(R.id.xListView); mListView.setPullLoadEnable(true); mListView.setRemoveListener(this); mListView.setOnItemClickListener(this); // mListView.setPullLoadEnable(false); // mListView.setPullRefreshEnable(false); mListView.setXListViewListener(this); adapter=new ItemAdapter(this); adapter.setData(items); mListView.setAdapter(adapter); } private void geneItems() { for (int i = 0; i != 20; ++i) { items.add("refresh cnt " + (++start)); } } private void onLoad() { mListView.stopRefresh(); mListView.stopLoadMore(); mListView.setRefreshTime("刚刚"); } @Override public void onRefresh() { mHandler.postDelayed(new Runnable() { @Override public void run() { start = ++refreshCnt; items.clear(); geneItems(); // mAdapter.notifyDataSetChanged(); adapter=new ItemAdapter(XListViewActivity.this); adapter.setData(items); mListView.setAdapter(adapter); onLoad(); } }, 2000); } @Override public void onLoadMore() { mHandler.postDelayed(new Runnable() { @Override public void run() { geneItems(); adapter.notifyDataSetChanged(); onLoad(); } }, 2000); } @Override public void removeItem(int position) { // TODO Auto-generated method stub mListView.isSlide = false; mListView.itemView.findViewById(R.id.tv_coating).setVisibility(View.VISIBLE); items.remove(position); adapter.notifyDataSetChanged(); } @Override public void onItemClick(AdapterView<?> parent, View view, int position, long id) { // TODO Auto-generated method stub Intent intent = new Intent(getApplicationContext(), ItemActivity.class); intent.putExtra("item", items.get(position)); startActivity(intent); overridePendingTransition(R.anim.slide_in_from_right, R.anim.remain_original_location); } } 自定义LIstView * * @file XListView.java * @package me.maxwin.view * @create Mar 18, 2012 6:28:41 PM * @author Maxwin * @description An ListView support (a) Pull down to refresh, (b) Pull up to load more. * Implement IXListViewListener, and see stopRefresh() / stopLoadMore(). */ package me.maxwin.view; import me.maxwin.R; import android.content.Context; import android.util.AttributeSet; import android.util.Log; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.View; import android.view.ViewConfiguration; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import android.view.animation.Animation; import android.view.animation.Animation.AnimationListener; import android.view.animation.DecelerateInterpolator; import android.view.animation.ScaleAnimation; import android.widget.AbsListView; import android.widget.AbsListView.OnScrollListener; import android.widget.AdapterView; import android.widget.ListAdapter; import android.widget.ListView; import android.widget.RelativeLayout; import android.widget.Scroller; import android.widget.TextView; public class XListView extends ListView implements OnScrollListener { private float mLastY = -1; // save event y private Scroller mScroller; // used for scroll back private OnScrollListener mScrollListener; // user's scroll listener // the interface to trigger refresh and load more. private IXListViewListener mListViewListener; // -- header view private XListViewHeader mHeaderView; // header view content, use it to calculate the Header's height. And hide it // when disable pull refresh. private RelativeLayout mHeaderViewContent; private TextView mHeaderTimeView; private int mHeaderViewHeight; // header view's height private boolean mEnablePullRefresh = true; private boolean mPullRefreshing = false; // is refreashing. // -- footer view private XListViewFooter mFooterView; private boolean mEnablePullLoad; private boolean mPullLoading; private boolean mIsFooterReady = false; // total list items, used to detect is at the bottom of listview. private int mTotalItemCount; // for mScroller, scroll back from header or footer. private int mScrollBack; private final static int SCROLLBACK_HEADER = 0; private final static int SCROLLBACK_FOOTER = 1; private final static int SCROLL_DURATION = 400; // scroll back duration private final static int PULL_LOAD_MORE_DELTA = 50; // when pull up >= 50px // at bottom, trigger // load more. private final static float OFFSET_RADIO = 1.8f; // support iOS like pull // feature. private int slidePosition, preSlidePosition; private int downY; private int downX; public static View itemView, preItemView; // private Scroller scroller; private static final int SNAP_VELOCITY = 600; private VelocityTracker velocityTracker; public static boolean isSlide = false; private boolean isResponse = true; public static boolean isObstruct = true; private int mTouchSlop; private RemoveListener mRemoveListener; private static Animation scaleHideAnimation; private static Animation scaleShowAnimation; /** * @param context */ public XListView(Context context) { super(context); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public XListView(Context context, AttributeSet attrs) { super(context, attrs); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } public XListView(Context context, AttributeSet attrs, int defStyle) { super(context, attrs, defStyle); // mScroller = new Scroller(context, new DecelerateInterpolator()); initWithContext(context); mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop(); } private void initWithContext(Context context) { mScroller = new Scroller(context, new DecelerateInterpolator()); // XListView need the scroll event, and it will dispatch the event to // user's listener (as a proxy). super.setOnScrollListener(this); // init header view mHeaderView = new XListViewHeader(context); mHeaderViewContent = (RelativeLayout) mHeaderView .findViewById(R.id.xlistview_header_content); mHeaderTimeView = (TextView) mHeaderView .findViewById(R.id.xlistview_header_time); addHeaderView(mHeaderView); // init footer view mFooterView = new XListViewFooter(context); // init header height mHeaderView.getViewTreeObserver().addOnGlobalLayoutListener( new OnGlobalLayoutListener() { @Override public void onGlobalLayout() { mHeaderViewHeight = mHeaderViewContent.getHeight(); getViewTreeObserver() .removeGlobalOnLayoutListener(this); } }); } @Override public void setAdapter(ListAdapter adapter) { // make sure XListViewFooter is the last footer view, and only add once. if (mIsFooterReady == false) { mIsFooterReady = true; addFooterView(mFooterView); } super.setAdapter(adapter); } /** * enable or disable pull down refresh feature. * * @param enable */ public void setPullRefreshEnable(boolean enable) { mEnablePullRefresh = enable; if (!mEnablePullRefresh) { // disable, hide the content mHeaderViewContent.setVisibility(View.INVISIBLE); } else { mHeaderViewContent.setVisibility(View.VISIBLE); } } /** * enable or disable pull up load more feature. * * @param enable */ public void setPullLoadEnable(boolean enable) { mEnablePullLoad = enable; if (!mEnablePullLoad) { mFooterView.hide(); mFooterView.setOnClickListener(null); } else { mPullLoading = false; mFooterView.show(); mFooterView.setState(XListViewFooter.STATE_NORMAL); // both "pull up" and "click" will invoke load more. mFooterView.setOnClickListener(new OnClickListener() { @Override public void onClick(View v) { startLoadMore(); } }); } } /** * stop refresh, reset header view. */ public void stopRefresh() { if (mPullRefreshing == true) { mPullRefreshing = false; resetHeaderHeight(); } } /** * stop load more, reset footer view. */ public void stopLoadMore() { if (mPullLoading == true) { mPullLoading = false; mFooterView.setState(XListViewFooter.STATE_NORMAL); } } /** * set last refresh time * * @param time */ public void setRefreshTime(String time) { mHeaderTimeView.setText(time); } private void invokeOnScrolling() { if (mScrollListener instanceof OnXScrollListener) { OnXScrollListener l = (OnXScrollListener) mScrollListener; l.onXScrolling(this); } } private void updateHeaderHeight(float delta) { mHeaderView.setVisiableHeight((int) delta + mHeaderView.getVisiableHeight()); if (mEnablePullRefresh && !mPullRefreshing) { // 未处于刷新状态,更新箭头 if (mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mHeaderView.setState(XListViewHeader.STATE_READY); } else { mHeaderView.setState(XListViewHeader.STATE_NORMAL); } } setSelection(0); // scroll to top each time } /** * reset header view's height. */ private void resetHeaderHeight() { int height = mHeaderView.getVisiableHeight(); if (height == 0) // not visible. return; // refreshing and header isn't shown fully. do nothing. if (mPullRefreshing && height <= mHeaderViewHeight) { return; } int finalHeight = 0; // default: scroll back to dismiss header. // is refreshing, just scroll back to show all the header. if (mPullRefreshing && height > mHeaderViewHeight) { finalHeight = mHeaderViewHeight; } mScrollBack = SCROLLBACK_HEADER; mScroller.startScroll(0, height, 0, finalHeight - height, SCROLL_DURATION); // trigger computeScroll invalidate(); } private void updateFooterHeight(float delta) { int height = mFooterView.getBottomMargin() + (int) delta; if (mEnablePullLoad && !mPullLoading) { if (height > PULL_LOAD_MORE_DELTA) { // height enough to invoke load // more. mFooterView.setState(XListViewFooter.STATE_READY); } else { mFooterView.setState(XListViewFooter.STATE_NORMAL); } } mFooterView.setBottomMargin(height); // setSelection(mTotalItemCount - 1); // scroll to bottom } private void resetFooterHeight() { int bottomMargin = mFooterView.getBottomMargin(); if (bottomMargin > 0) { mScrollBack = SCROLLBACK_FOOTER; mScroller.startScroll(0, bottomMargin, 0, -bottomMargin, SCROLL_DURATION); invalidate(); } } private void startLoadMore() { mPullLoading = true; mFooterView.setState(XListViewFooter.STATE_LOADING); if (mListViewListener != null) { mListViewListener.onLoadMore(); } } //RemoveListener public void setRemoveListener(RemoveListener removeListener) { this.mRemoveListener = removeListener; } public boolean dispatchTouchEvent(MotionEvent event) { switch (event.getAction()) { case MotionEvent.ACTION_DOWN: { Log.e("lg", "dispatchTouchEvent ACTION_DOWN isSlide1111 = " + isSlide); addVelocityTracker(event); downX = (int) event.getX(); downY = (int) event.getY(); slidePosition = pointToPosition(downX, downY); if (slidePosition == AdapterView.INVALID_POSITION) { return super.dispatchTouchEvent(event); } if (preItemView != null && preItemView.findViewById(R.id.tv_coating).getVisibility() == View.GONE) { itemView = preItemView; slidePosition = preSlidePosition; } else { itemView = getChildAt(slidePosition - getFirstVisiblePosition()); preItemView = itemView; preSlidePosition = slidePosition; } break; } case MotionEvent.ACTION_MOVE: { if (Math.abs(getScrollVelocity()) > SNAP_VELOCITY || (Math.abs(event.getX() - downX) > mTouchSlop && Math.abs(event.getY() - downY) < mTouchSlop)) { isSlide = true; } break; } case MotionEvent.ACTION_UP: recycleVelocityTracker(); isObstruct = true; break; } return super.dispatchTouchEvent(event); } public boolean onInterceptTouchEvent(MotionEvent ev) { switch (ev.getAction()) { case MotionEvent.ACTION_MOVE: if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.VISIBLE) { isSlide = false; } else { isSlide = true; } break; default: break; } return super.onInterceptTouchEvent(ev); } //dispatchTouchEvent ACTION_DOWN isSlide // @Override dispatchTouchEvent public boolean onTouchEvent(MotionEvent ev) { if (isSlide && slidePosition != AdapterView.INVALID_POSITION) { addVelocityTracker(ev); final int action = ev.getAction(); switch (action) { case MotionEvent.ACTION_MOVE: if (isObstruct) { if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.VISIBLE && isResponse == true) { scaleHideAnimation = new ScaleAnimation(1.0f, 0.0f, 1.0f, 1.0f); scaleHideAnimation.setDuration(250); scaleHideAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { isResponse = false; isObstruct = false; } public void onAnimationRepeat(Animation animation) { } public void onAnimationEnd(Animation animation) { isResponse = true; itemView.findViewById(R.id.tv_coating).setVisibility(View.GONE); itemView.findViewById(R.id.tv_functions).setClickable(true); itemView.findViewById(R.id.tv_functions).setOnClickListener(new OnClickListener() { public void onClick(View v) { mRemoveListener.removeItem(slidePosition); } }); } }); itemView.findViewById(R.id.tv_coating).startAnimation(scaleHideAnimation); } else if (itemView.findViewById(R.id.tv_coating).getVisibility() == View.GONE && isResponse == true) { scaleShowAnimation = new ScaleAnimation(0.0f, 1.0f, 1.0f, 1.0f); scaleShowAnimation.setDuration(250); scaleShowAnimation.setAnimationListener(new AnimationListener() { public void onAnimationStart(Animation animation) { isResponse = false; isObstruct = false; } public void onAnimationRepeat(Animation animation) { } public void onAnimationEnd(Animation animation) { isSlide = false; isResponse = true; itemView.findViewById(R.id.tv_coating).setVisibility(View.VISIBLE); } }); itemView.findViewById(R.id.tv_coating).startAnimation(scaleShowAnimation); } } break; case MotionEvent.ACTION_UP: isObstruct = true; recycleVelocityTracker(); isSlide = true; break; } return true; } if (mLastY == -1) { mLastY = ev.getRawY(); } switch (ev.getAction()) { case MotionEvent.ACTION_DOWN: mLastY = ev.getRawY(); break; case MotionEvent.ACTION_MOVE: final float deltaY = ev.getRawY() - mLastY; mLastY = ev.getRawY(); if (getFirstVisiblePosition() == 0 && (mHeaderView.getVisiableHeight() > 0 || deltaY > 0)) { // the first item is showing, header has shown or pull down. updateHeaderHeight(deltaY / OFFSET_RADIO); invokeOnScrolling(); } else if (getLastVisiblePosition() == mTotalItemCount - 1 && (mFooterView.getBottomMargin() > 0 || deltaY < 0)) { // last item, already pulled up or want to pull up. updateFooterHeight(-deltaY / OFFSET_RADIO); } break; default: mLastY = -1; // reset if (getFirstVisiblePosition() == 0) { // invoke refresh if (mEnablePullRefresh && mHeaderView.getVisiableHeight() > mHeaderViewHeight) { mPullRefreshing = true; mHeaderView.setState(XListViewHeader.STATE_REFRESHING); if (mListViewListener != null) { mListViewListener.onRefresh(); } } resetHeaderHeight(); } else if (getLastVisiblePosition() == mTotalItemCount - 1) { // invoke load more. if (mEnablePullLoad && mFooterView.getBottomMargin() > PULL_LOAD_MORE_DELTA && !mPullLoading) { startLoadMore(); } resetFooterHeight(); } break; } return super.onTouchEvent(ev); // return super.onTouchEvent(ev); } @Override public void computeScroll() { if (mScroller.computeScrollOffset()) { if (mScrollBack == SCROLLBACK_HEADER) { mHeaderView.setVisiableHeight(mScroller.getCurrY()); } else { mFooterView.setBottomMargin(mScroller.getCurrY()); } postInvalidate(); invokeOnScrolling(); if (mScroller.isFinished()) { if (mRemoveListener == null) { throw new NullPointerException("RemoveListener is null, we should called setRemoveListener()"); } itemView.scrollTo(0, 0); } } super.computeScroll(); } //addVelocityTracker private void addVelocityTracker(MotionEvent event) { if (velocityTracker == null) { velocityTracker = VelocityTracker.obtain(); } velocityTracker.addMovement(event); } private void recycleVelocityTracker() { if (velocityTracker != null) { velocityTracker.recycle(); velocityTracker = null; } } private int getScrollVelocity() { velocityTracker.computeCurrentVelocity(1000); int velocity = (int) velocityTracker.getXVelocity(); return velocity; } public interface RemoveListener { public void removeItem(int position); } @Override public void setOnScrollListener(OnScrollListener l) { mScrollListener = l; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { if (mScrollListener != null) { mScrollListener.onScrollStateChanged(view, scrollState); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { // send to user's listener mTotalItemCount = totalItemCount; if (mScrollListener != null) { mScrollListener.onScroll(view, firstVisibleItem, visibleItemCount, totalItemCount); } } public void setXListViewListener(IXListViewListener l) { mListViewListener = l; } /** * you can listen ListView.OnScrollListener or this one. it will invoke * onXScrolling when header/footer scroll back. */ public interface OnXScrollListener extends OnScrollListener { public void onXScrolling(View view); } /** * implements this interface to get refresh/load more event. */ public interface IXListViewListener { public void onRefresh(); public void onLoadMore(); } }

2015-05-04

空空如也

TA创建的收藏夹 TA关注的收藏夹

TA关注的人

提示
确定要删除当前文章?
取消 删除