android汽车之家顶部滑动菜单,Android自定义控件之仿汽车之家下拉刷新
关于下拉刷新的实现原理我在上篇文章Android自定义控件之仿美团下拉刷新中已经详细介绍过了,这篇文章主要介绍表盘的动画实现原理
汽车之家的下拉刷新分为三个状态:
第一个状态为下拉刷新状态(pull to refresh),在这个状态下是一个表盘随着下拉的距离动态改变指针的角度
第二个状态为放开刷新状态(release to refresh),在这个状态下是指针角度变化的一个动画
第一个状态的实现:
这个效果我们使用自定义View来实现,我们从汽车之家apk中拿到下拉刷新所用到的两张图片:
我们将第一张图片画在画布上作为背景,接着我们根据当前进度值来动态旋转画布,然后再将第二章图片画在画布上,我们看到表针的旋转实则是画布在旋转。
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//现将第一张图片画在画布上
canvas.drawBitmap(finalBackGroundBitmap,0,0,null);
//旋转画布
canvas.rotate(mCurrentProgress*2.7f,x/2,y/2);
//将第二张图片画在旋转后的画布上
canvas.drawBitmap(finalPointerBitmap, 0, 0, null);
}
自定义View的完整代码如下:
/**
* Created by zhangqi on 15/10/17.
*/
public class AutoHome extends View{
private Bitmap backGroundBitmap;
public Bitmap pointerBitmap;
private int x;
private int y;
private Bitmap finalBackGroundBitmap;
private Bitmap finalPointerBitmap;
private float mCurrentProgress;
public AutoHome(Context context) {
super(context);
init(context);
}
public AutoHome(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public AutoHome(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context);
}
private void init(Context context) {
backGroundBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.load_icon_dial2x));
pointerBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(context.getResources(), R.drawable.load_icon_pointer2x));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(heightMeasureSpec));
x = getMeasuredWidth();
y = getMeasuredHeight();
finalBackGroundBitmap = Bitmap.createScaledBitmap(backGroundBitmap, x, y, false);
finalPointerBitmap = Bitmap.createScaledBitmap(pointerBitmap, x, y, false);
}
private int measureWidth(int widMeasureSpec){
int result = 0;
int size = MeasureSpec.getSize(widMeasureSpec);
int mode = MeasureSpec.getMode(widMeasureSpec);
if (mode == MeasureSpec.EXACTLY){
result = size;
}else{
result = backGroundBitmap.getWidth();
if (mode == MeasureSpec.AT_MOST){
result = Math.min(result,size);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawBitmap(finalBackGroundBitmap,0,0,null);
canvas.rotate(mCurrentProgress*2.7f,x/2,y/2);
canvas.drawBitmap(finalPointerBitmap, 0, 0, null);
}
public void setCurrentProgress(float progress){
mCurrentProgress = progress*100;
}
}
接着我们在Activity中用SeekBar来模拟一个进度值,从而传递给我们自定义View
public class MainActivity extends AppCompatActivity {
private SeekBar mSeekBar;
private AutoHome mAutoHome;
private float mCurrentProgress;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mSeekBar = (SeekBar) findViewById(R.id.seekbar);
mAutoHome = (AutoHome) findViewById(R.id.autohome);
mSeekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() {
@Override
public void onProgressChanged(SeekBar seekBar, int i, boolean b) {
mCurrentProgress = (float)seekBar.getProgress()/(float)seekBar.getMax();
mAutoHome.setCurrentProgress(mCurrentProgress);
mAutoHome.invalidate();
}
@Override
public void onStartTrackingTouch(SeekBar seekBar) {
}
@Override
public void onStopTrackingTouch(SeekBar seekBar) {
}
});
}
第二个状态的实现:
第二个状态是表针在执行一个旋转的动画,我们可以将表针写成一个自定义View,然后表盘作为背景图片,然后表针View来执行rotate动画即可
/**
* Created by zhangqi on 15/10/27.
*/
public class PointerView extends View {
private int x;
private int y;
private Bitmap finalPointerBitmap;
private Bitmap pointerBitmap;
public PointerView(Context context) {
super(context);
init();
}
public PointerView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public PointerView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
private void init() {
pointerBitmap = Bitmap.createBitmap(BitmapFactory.decodeResource(getResources(), R.drawable.load_icon_pointer2x));
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
setMeasuredDimension(measureWidth(widthMeasureSpec),measureWidth(heightMeasureSpec));
x = getMeasuredWidth();
y = getMeasuredHeight();
finalPointerBitmap = Bitmap.createScaledBitmap(pointerBitmap, x, y, false);
}
private int measureWidth(int widMeasureSpec){
int result = 0;
int size = MeasureSpec.getSize(widMeasureSpec);
int mode = MeasureSpec.getMode(widMeasureSpec);
if (mode == MeasureSpec.EXACTLY){
result = size;
}else{
result = pointerBitmap.getWidth();
if (mode == MeasureSpec.AT_MOST){
result = Math.min(result,size);
}
}
return result;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//目的是让表针初始位置为270度!
canvas.rotate(270,x/2,y/2);
canvas.drawBitmap(finalPointerBitmap,0,0,null);
}
}
然后我们在xml文件中这样写:
android:layout_width="45dp"
android:layout_height="45dp"
android:layout_margin="15dp"
android:visibility="gone" >
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
android:layout_height="wrap_content"
android:src="@drawable/load_icon_dial2x" />
这样就将表盘作为背景了,我们可以操作表针来执行rotate动画
android:fromDegrees="0"
android:toDegrees="-150"
android:pivotY="50%"
android:pivotX="50%"
android:duration="1000"
android:repeatCount="infinite"
android:repeatMode="reverse"
>
mAutoHomeAnim = (PointerView) headerView.findViewById(R.id.anim_pointer);
animation = AnimationUtils.loadAnimation(context, R.anim.pointer_rotate);
//执行动画
mAutoHomeAnim.startAnimation(animation);
在listview中
由于下拉刷新核心代码和美团下拉刷新是一样的,这里我只截取不一样的部分
private void changeHeaderByState(int state){
switch (state) {
case DONE:
headerView.setPadding(0, -headerViewHeight, 0, 0);
//第一状态的view显示出来
mAutoHome.setVisibility(View.VISIBLE);
//先停止一下第二阶段view的动画
mAutoHomeAnim.clearAnimation();
//将第二阶段view隐藏起来
mAnimContainer.setVisibility(View.GONE);
break;
case RELEASE_TO_REFRESH:
tv_pull_to_refresh.setText("放开刷新");
break;
case PULL_TO_REFRESH:
tv_pull_to_refresh.setText("下拉刷新");
//第一状态view显示出来
mAutoHome.setVisibility(View.VISIBLE);
//停止第二阶段动画
mAutoHomeAnim.clearAnimation();
//将第二阶段view隐藏
mAnimContainer.setVisibility(View.GONE);
break;
case REFRESHING:
tv_pull_to_refresh.setText("正在刷新");
//将第一阶段view隐藏
mAutoHome.setVisibility(View.GONE);
//将第二阶段view显示出来
mAnimContainer.setVisibility(View.VISIBLE);
//先停止第二阶段动画
mAutoHomeAnim.clearAnimation();
//启动第二阶段动画
mAutoHomeAnim.startAnimation(animation);
break;
default:
break;
}
}
完整代码:
大家可以到我的GitHub上下载
android汽车之家顶部滑动菜单,Android自定义控件之仿汽车之家下拉刷新相关推荐
- Android【Toolbar、DrawerLayout 滑动菜单、 FloatingActionButton 悬浮按钮、Snackbar可交互提示、 Coordinator】
目录 1.Toolbar 1.1基本框架 1.2常用属性 1.3添加工具栏点击事件 1.4 溢出菜单 1.5 溢出菜单的点击事件 2 DrawerLayout 滑动菜单 2.1 基本框架 2.2 Na ...
- Android自定义控制(五)仿新浪微博的下拉刷新
网上有很多很有名的开源框架,这里就来拉拉PullToRefresh这个框架,也就是我们平时用的下拉刷新啦,当然你问我这个有什么用啊?别人已经写好了,这里主要是学习以及练习,练习的次数多了,一切就顺其自 ...
- Android仿苹果版QQ下拉刷新实现(二) ——贝塞尔曲线开发鼻涕下拉粘连效果
前言 接着上一期 Android仿苹果版QQ下拉刷新实现(一) --打造简单平滑的通用下拉刷新控件 的博客开始,同样,在开始前我们先来看一下目标效果: 下面上一下本章需要实现的效果图: 大家看到这个效 ...
- Android仿苹果版QQ下拉刷新实现(三)
前言 第三篇下拉刷新的博客来的稍微有点晚,因为前两篇的博客访问量一直不是很高,所以博主花了点时间修改了整体的Demo效果,处理了很多极端下拉情况下的显示问题,给大家呈现一个完美的下拉刷新控件.因为本文 ...
- 汽车之家跃升“头号引擎”,今年818全球汽车节有哪些看点?
文 | 曾响铃 来源 | 科技向令说(xiangling0815) 如果说双11.618是淘宝和京东送给网购者最好的礼物,那么"818全球汽车节"就是汽车之家为购车用户打造的节日狂 ...
- AutoHomeRefreshListView仿汽车之家下拉刷新 《IT蓝豹》
2019独角兽企业重金招聘Python工程师标准>>> AutoHomeRefreshListView仿汽车之家下拉刷新 AutoHomeRefreshListView 高仿汽车之家 ...
- android qq弹出菜单,Android开发实现qqminihd 左右滑动菜单效果
类型:编程工具大小:13.8M语言:英文 评分:5.5 标签: 立即下载 观察qqminihd界面,发现其界面能够左右滑动来实现两侧菜单效果. 自定义Layout:ScrollLayout.java ...
- 011 Android TabLayout+ViewPager实现顶部滑动效果(多个页面)
1.TabLayout介绍 TabLayout提供了一个水平的布局用来展示Tabs,很多应用都有这样的设计,典型的有网易新闻,简书,知乎等.TabLayout就可以很好的完成这一职责,首先TabLay ...
- Android自定义控件之仿汽车之家下拉刷新
感谢 阿拉灯神灯 的技术分享 .版权声明:原文来自http://blog.csdn.net/nugongahou110 关于下拉刷新的实现原理我在上篇文章Android自定义控件之仿美团下拉刷新中已经 ...
最新文章
- jQuery性能优化指南
- apache php ffmpeg,linux(php环境) 安装ffmpeg
- 来自iSpy整理的最全海康大华IPC的RTSP连接地址
- Behavior Designer
- 某工程车零部件制造厂商
- Java--transient
- [Git] warning: Clone succeeded, but checkout failed.
- 【转】Java程序员最常用的8个Java日志框架
- 手机如何在线图片识别?3大教程,一键轻松图片转文字
- MySQL - 实战 棋牌游戏数据库开发
- 如何在2015年后的MacBook Air上安装双系统
- 关于Mac系统 使用npm i xxx的时候 报错
- 查找数据库指定数据的数据表和字段名称SQL语句
- linux篇【12】:网络套接字<前序>—网络基础+udp套接字
- 欢迎高校使用云创大数据的高质量大数据和人工智能免费直播授课!
- md+邮件服务器+334错误,邮件发送,无尽的501错误。TCP发送邮件解决方案
- 方便又高效,这几款远程办公软件值得学习
- 非计算机专业人员的程序之路
- 我们只是虫子!我们真的是虫子吗?
- 武汉软通动力之武汉未来科技城面试题(2018.5.7)