700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > android汽车之家顶部滑动菜单 Android自定义控件之仿汽车之家下拉刷新

android汽车之家顶部滑动菜单 Android自定义控件之仿汽车之家下拉刷新

时间:2022-09-16 02:55:33

相关推荐

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上下载

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。