Android實(shí)現(xiàn)類似ios滑動(dòng)按鈕
IOS的滑動(dòng)按鈕菜單在UI設(shè)計(jì)里面絕對(duì)堪稱一絕,在學(xué)習(xí)了Android的自定義view后,我萌生了模仿它的想法。


實(shí)現(xiàn)上面的模擬需要自定義一個(gè)View;
1)、在View的OnDraw里畫(huà)出圓角矩形,分別為灰色圓角矩形,紅色圓角矩形,和綠色圓角矩形。然后計(jì)算相應(yīng)的位置。
2)、本例中的寬高比為1:0.65,內(nèi)部紅色矩形尺寸為外部矩形尺寸0.9,內(nèi)部的圓的半徑為外部高的0.45倍。按照這個(gè)比例計(jì)算相應(yīng)的坐標(biāo)。
3)、本例中的動(dòng)畫(huà)是用ValueAnimation實(shí)現(xiàn)的,具體實(shí)現(xiàn)在下部代碼中。
4)、本例中的透明度實(shí)現(xiàn)方法和運(yùn)動(dòng)動(dòng)畫(huà)一樣。
5)、自定義View為外部提供了讀取和修改內(nèi)部狀態(tài)的接口。
具體代碼如下,
1、界面的XML代碼:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/activity_switch_button"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.app_switchbutton.SwitchButtonActivity">
<com.example.app_switchbutton.switchbutton
android:id="@+id/button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_alignParentStart="true" />
<com.example.app_switchbutton.switchbutton
android:layout_width="100dp"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"/>
</RelativeLayout>
2、實(shí)現(xiàn)自定義view的java代碼:
package com.example.app_switchbutton;
import android.animation.ValueAnimator;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.widget.RadioButton;
/**
* Created by 盡途 on 2017/4/26.
*/
public class switchbutton extends View {
private int widthSize;
private int heightSize;
private boolean isOn=false;
private float WhiteRoundRect_width,WhiteRoundRect_height;
private float Circle_X,Circle_Y,WhiteRoundRect_X,WhiteRoundRect_Y;
private float Radius;
private float currentValue;
private int currentAlphaofGreen,currentAlphaofGray;
public switchbutton(Context context){
super(context);
}
public switchbutton(Context context, AttributeSet attributeSet){
super(context,attributeSet);
setLayerType(LAYER_TYPE_SOFTWARE,null);
initData();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
widthSize=MeasureSpec.getSize(widthMeasureSpec);
heightSize=(int)(widthSize*0.65f);
setMeasuredDimension(widthSize,heightSize);
initData();
}
void initData(){
if (isOn){
currentValue=widthSize-0.5f*heightSize;
currentAlphaofGreen=255;
currentAlphaofGray=0;
}
else {
currentValue=0.5f*heightSize;
currentAlphaofGreen=0;
currentAlphaofGray=255;
}
}
@Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
super.onSizeChanged(w, h, oldw, oldh);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
if (isOn){
DrawBackGreenRoundRect(canvas);
DrawCircle(canvas);
}
else {
DrawBackGrayRoundRect(canvas);
DrawBackWhiteRoundRect(canvas);
DrawCircle(canvas);
}
}
private void DrawBackGrayRoundRect(Canvas canvas){
Paint paint0=new Paint();
paint0.setStyle(Paint.Style.FILL);
paint0.setColor(Color.GRAY);
paint0.setAntiAlias(true);
paint0.setAlpha(currentAlphaofGray);
RectF roundRect=new RectF(0,0,widthSize,heightSize);
canvas.drawRoundRect(roundRect,heightSize*0.5f,heightSize*0.5f,paint0);
}
private void DrawBackGreenRoundRect(Canvas canvas){
Paint paint1=new Paint();
paint1.setStyle(Paint.Style.FILL);
paint1.setColor(Color.GREEN);
paint1.setAntiAlias(true);
paint1.setAlpha(currentAlphaofGreen);
RectF roundRect=new RectF(0,0,widthSize,heightSize);
canvas.drawRoundRect(roundRect,heightSize*0.5f,heightSize*0.5f,paint1);
}
private void DrawCircle(Canvas canvas){
Circle_Y=heightSize*0.5f;
Radius=heightSize*0.45f;
Paint paint2=new Paint();
paint2.setStyle(Paint.Style.FILL);
paint2.setColor(Color.WHITE);
paint2.setAntiAlias(true);
canvas.drawCircle(currentValue,Circle_Y,Radius,paint2);
}
private void DrawBackWhiteRoundRect(Canvas canvas){
Paint paint3=new Paint();
paint3.setStyle(Paint.Style.FILL);
paint3.setColor(Color.RED);
paint3.setAntiAlias(true);
paint3.setAlpha(currentAlphaofGray);
WhiteRoundRect_X=heightSize*0.05f;
WhiteRoundRect_Y=heightSize*0.05f;
WhiteRoundRect_width=widthSize-0.05f*heightSize;
WhiteRoundRect_height=heightSize*0.95f;
RectF rectf=new RectF(WhiteRoundRect_X,WhiteRoundRect_Y,WhiteRoundRect_width,WhiteRoundRect_height);
canvas.drawRoundRect(rectf,WhiteRoundRect_height*0.5f,WhiteRoundRect_height*0.5f,paint3);
}
/**
* 添加了過(guò)渡值動(dòng)畫(huà),實(shí)現(xiàn)了平緩運(yùn)動(dòng)
* @param startValue
* @param endValue
*/
private void setAnimation(float startValue,float endValue){
ValueAnimator valueAnimator=ValueAnimator.ofFloat(startValue,endValue);
valueAnimator.setDuration(1500);
valueAnimator.setTarget(currentValue);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentValue=(float)animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
private void setAlphaAnimationofGray(int startValue,int endValue){
ValueAnimator valueAnimator=ValueAnimator.ofInt(startValue,endValue);
valueAnimator.setDuration(1500);
valueAnimator.setTarget(currentAlphaofGray);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAlphaofGray=(int)animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
private void setAlphaAnimationofGreen(int startValue,int endValue){
ValueAnimator valueAnimator=ValueAnimator.ofInt(startValue,endValue);
valueAnimator.setDuration(1500);
valueAnimator.setTarget(currentAlphaofGreen);
valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
currentAlphaofGreen=(int)animation.getAnimatedValue();
invalidate();
}
});
valueAnimator.start();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
return true;
case MotionEvent.ACTION_MOVE:
return false;
case MotionEvent.ACTION_UP:
isOn=!isOn;
invalidate();
break;
default:
break;
}
if (isOn){
float startCircle_X=0.5f*heightSize;
float endCircle_X=widthSize-0.5f*heightSize;
setAnimation(startCircle_X,endCircle_X);
setAlphaAnimationofGray(255,0);
setAlphaAnimationofGreen(0,255);
}else {
float startCircle_X=widthSize-0.5f*heightSize;
float endCircle_X=heightSize*0.5f;
setAnimation(startCircle_X,endCircle_X);
setAlphaAnimationofGray(0,255);
setAlphaAnimationofGreen(255,0);
}
return super.onTouchEvent(event);
}
public void writeSwitchButtonState(boolean isOn){
this.isOn=isOn;
}
public boolean readSwitchButtonState(){
return isOn;
}
}
模仿的不是很到位,請(qǐng)大家見(jiàn)諒。
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android DragImageView實(shí)現(xiàn)下拉拖動(dòng)圖片放大效果
這篇文章主要為大家詳細(xì)介紹了Android DragImageView實(shí)現(xiàn)下拉拖動(dòng)圖片放大效果,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-12-12
Android ListView下拉刷新上拉自動(dòng)加載更多DEMO示例
這篇文章主要介紹了Android ListView下拉刷新上拉自動(dòng)加載更多DEMO示例的相關(guān)資料,非常不錯(cuò),具有參考借鑒價(jià)值,需要的朋友可以參考下2016-07-07
Android?自定義View?加?lifecycle?簡(jiǎn)單使用詳解
本文介紹了自定義View的基本使用方法,包括onMeasure、onDraw、自定義樣式和lifecycle的使用,通過(guò)了解MeasureSpec的作用和lifecycle的控制,可以更好地管理View的生命周期,避免內(nèi)存泄露問(wèn)題,感興趣的朋友一起看看吧2025-03-03
詳解Android(共享元素)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)開(kāi)發(fā)實(shí)踐
本篇文章主要介紹了詳解Android(共享元素)轉(zhuǎn)場(chǎng)動(dòng)畫(huà)開(kāi)發(fā)實(shí)踐,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2017-08-08
Android自定義View實(shí)現(xiàn)QQ音樂(lè)中圓形旋轉(zhuǎn)碟子
這篇文章主要為大家詳細(xì)介紹了Android自定義View實(shí)現(xiàn)QQ音樂(lè)中圓形旋轉(zhuǎn)碟子,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2016-09-09
Android React-Native通信數(shù)據(jù)模型分析
這篇文章主要介紹了Android React-Native通信數(shù)據(jù)模型分析的相關(guān)資料,需要的朋友可以參考下2016-10-10
Flutter 全局點(diǎn)擊空白處隱藏鍵盤(pán)實(shí)戰(zhàn)
這篇文章主要介紹了Flutter 全局點(diǎn)擊空白處隱藏鍵盤(pán)實(shí)戰(zhàn),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-09-09
Android實(shí)現(xiàn)調(diào)用震動(dòng)的方法
這篇文章主要介紹了Android實(shí)現(xiàn)調(diào)用震動(dòng)的方法,實(shí)例分析了Android中Vibrator類的調(diào)用與使用技巧,具有一定參考借鑒價(jià)值,需要的朋友可以參考下2015-11-11
Android ExpandableListView單選以及多選實(shí)現(xiàn)代碼
這篇文章主要為大家詳細(xì)介紹了Android ExpandableListView單選以及多選的實(shí)現(xiàn)代碼,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-06-06

