iOS的滑动解锁你的心系列(张翰梗)一直是个人觉得蛮好的看的一个东西,然后今天就把这样的一个控件应用到我们今天的Demo中让他滑动解锁。
样式是这样的:出处
流程–用户打开App–输入账号密码–滑动登录–正确/错误–登陆成功提示/弹出对话框。
很普遍的登陆流程,只是在具体实现上做一些改变,摆脱单一的登录,注册按钮等。
MainActivity:
public class MainActivity extends AppCompatActivity implements SlideBar.OnTriggerListener,OnTouchListener{
SlideBar slideToUnLock;
IconEditText users,password;
String User,Password;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
slideToUnLock = (SlideBar)findViewById(R.id.slideBar);
users=(IconEditText)findViewById(R.id.user);
password=(IconEditText)findViewById(R.id.password);
slideToUnLock.setOnTouchListener(this);
slideToUnLock.setOnTriggerListener(this);
}
@Override
public void onTrigger() {
Toast.makeText(this, getResources().
getString(R.string.unlock_string), Toast.LENGTH_SHORT).show();
}
void logic(){
User=users.getEditText().getText().toString();
Password=password.getEditText().getText().toString();
if(!User.equals("wjj")||!Password.equals("123")){
dialog();
}
}
@Override
public boolean onTouch(View v, MotionEvent event) {
int action=event.getAction();
switch (action){
case MotionEvent.ACTION_DOWN:
logic();
break;
}
return false;
}
public void dialog() {
AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
builder.setMessage("이 잘못된 비밀번호");
builder.setTitle("참고 소식");
builder.setPositiveButton("알았어.", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
});
builder.create().show();
}
@Override
public boolean onCreateOptionsMenu(Menu menu) {
// Inflate the menu; this adds items to the action bar if it is present.
getMenuInflater().inflate(R.menu.menu_main, menu);
return true;
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
// Handle action bar item clicks here. The action bar will
// automatically handle clicks on the Home/Up button, so long
// as you specify a parent activity in AndroidManifest.xml.
int id = item.getItemId();
//noinspection SimplifiableIfStatement
if (id == R.id.action_settings) {
return true;
}
return super.onOptionsItemSelected(item);
}
}
主布局
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:widget="http://schemas.android.com/apk/res-auto"
xmlns:prvandroid="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity"
android:background="@drawable/bg">
<RelativeLayout
android:layout_marginLeft="40dp"
android:layout_marginRight="40dp"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_centerVertical="true"
android:layout_centerHorizontal="true">
<logdemo.wjj.com.logdemo.Custom.IconEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#ffffff"
widget:hint="@string/user_name"
widget:iconSrc="@mipmap/users"
android:id="@+id/user"
widget:isPassword="false"
android:background="@drawable/layout_bg">
</logdemo.wjj.com.logdemo.Custom.IconEditText>
<logdemo.wjj.com.logdemo.Custom.IconEditText
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:textColorHint="#ffffff"
widget:hint="@string/password"
widget:iconSrc="@mipmap/lock"
android:id="@+id/password"
widget:isPassword="true"
android:layout_below="@id/user"
android:layout_marginTop="30dp"
android:background="@drawable/layout_bg">
</logdemo.wjj.com.logdemo.Custom.IconEditText>
</RelativeLayout>
<logdemo.wjj.com.logdemo.Custom.SlideBar
android:id="@+id/slideBar"
android:layout_width="@dimen/slide_bar_width"
android:layout_height="@dimen/slide_bar_height"
android:layout_centerHorizontal="true"
android:layout_alignParentBottom="true"
android:layout_marginBottom="20dip"
android:background="@drawable/layout_bg"
prvandroid:MinVelocityXToUnlock="1500"
prvandroid:MinDistanceToUnlock="240"
prvandroid:LeftAnimationDuratioin="200"
prvandroid:RightAnimationDuratioin="300">
<logdemo.wjj.com.logdemo.Custom.GradientView
android:id="@+id/gradientView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerVertical="true"
android:layout_marginLeft="@dimen/gradient_view_margin_left"
prvandroid:StringToShow="@string/slide_to_unlock_string"
prvandroid:TextSize="@dimen/gradient_text_size"
prvandroid:TextColor="@color/gradient_text_color"
prvandroid:SlideColor="@color/gradient_slide_text_color"/>
</logdemo.wjj.com.logdemo.Custom.SlideBar>
</RelativeLayout>
IconEditText:http://blog.csdn.net/ddwhan0123/article/details/48654681
SlideBar,GradientView就是我们主要实现滑动解锁你的心的类了。
public class GradientView extends View {
private static final String TAG = "GradientView";
private static final boolean DEBUG = false;
private float mIndex = 0;
private Shader mShader;
private int mTextSize;
private static final int mUpdateStep = 15;
private static final int mMaxWidth = 40 * mUpdateStep; // 26*25
private static final int mMinWidth = 6 * mUpdateStep; // 5*25
int mDefaultColor;
int mSlideColor;
private ValueAnimator animator;
private int mWidth,mHeight;
private String mStringToShow;
private Paint mTextPaint;
private float mTextHeight;
private Drawable mSlideIcon;
private int mSlideIconHeight;
private static final int mSlideIconOffSetTop = 2;
private AnimatorUpdateListener mAnimatorUpdateListener = new AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
mIndex =Float.parseFloat(animation.getAnimatedValue().toString());
// RadialGradient SweepGradient
mShader = new LinearGradient(mIndex - 20 * mUpdateStep, 100,
mIndex, 100, new int[] { mDefaultColor, mDefaultColor, mDefaultColor,mSlideColor,
mSlideColor, mDefaultColor, mDefaultColor, mDefaultColor }, null,
Shader.TileMode.CLAMP);
postInvalidate();
}
};
public GradientView(Context context) {
super(context);
}
public GradientView(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.GradientView);
mStringToShow = a.getString(R.styleable.GradientView_StringToShow) ;
mTextSize = (int)a.getDimension(R.styleable.GradientView_TextSize, 40);
mDefaultColor = a.getColor(R.styleable.GradientView_TextColor, Color.GRAY);
mSlideColor = a.getColor(R.styleable.GradientView_SlideColor, Color.WHITE);
mSlideIcon = context.getResources().getDrawable(R.drawable.slide_icon);
mSlideIconHeight = mSlideIcon.getMinimumHeight();
a.recycle();
animator = ValueAnimator.ofFloat(mMinWidth,mMaxWidth);
animator.setDuration(1800);
animator.addUpdateListener(mAnimatorUpdateListener);
animator.setRepeatCount(Animation.INFINITE);//repeat animation
animator.start();
mTextPaint = new Paint();
mTextPaint.setAntiAlias(true);
mTextPaint.setColor(mSlideColor);
mTextPaint.setTextSize(mTextSize);
mTextPaint.setTextAlign(Paint.Align.CENTER);
mTextHeight = mTextPaint.ascent();
setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
if(DEBUG)
Log.w(TAG, "b onDraw()");
mTextPaint.setShader(mShader);
canvas.drawBitmap(((BitmapDrawable) mSlideIcon).getBitmap(), 20, mHeight
/ 2 - mSlideIconHeight / 2 + mSlideIconOffSetTop, null);
canvas.drawText(mStringToShow, mWidth / 2, mHeight / 2 - mTextHeight
/ 2 - mSlideIconOffSetTop, mTextPaint); // slide_unlock
}
public void stopAnimatorAndChangeColor() {
Log.w(TAG, "stopGradient");
animator.cancel();
//reset
mShader = new LinearGradient(0, 100, mIndex, 100,
new int[] {mSlideColor, mSlideColor},
null, Shader.TileMode.CLAMP);
invalidate();
}
public void startAnimator() {
if(DEBUG)
Log.w(TAG, "startGradient");
animator.start();
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
mWidth = MeasureSpec.getSize(widthMeasureSpec);
mHeight = MeasureSpec.getSize(heightMeasureSpec);
}
public void resetControl(){
animator.start();
this.setX(0);
invalidate();
}
}
SlideBar
public class SlideBar extends RelativeLayout {
private static final String TAG = "SlideBar";
private static final boolean DEBUG = false;
GradientView mGradientView ;
private int gradientViewStartX;
private float mEventDownX;
private float mGradientViewIndicateLeft;
private OnTriggerListener mOnTriggerListener;
private VelocityTracker mVelocityTracker = null;
private int mMinVelocityXToUnlock;
private int mMinDistanceToUnlock;
private int mLeftAnimationDuration;
private int mRightAnimationDuration;
private ObjectAnimator animLeftMoveAnimator;
private ObjectAnimator animRightMoveAnimator;
private static final int MaxDistance = 400;
public interface OnTriggerListener {
void onTrigger();
}
public SlideBar(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context, attrs);
}
public SlideBar(Context context){
super(context);
}
private void initView(Context context,AttributeSet attrs){
gradientViewStartX = context.getResources().
getDimensionPixelSize(R.dimen.gradient_view_margin_left) + 8;
TypedArray a = context.obtainStyledAttributes(attrs, R.styleable.SlideBar);
mMinVelocityXToUnlock = a.getInt(R.styleable.SlideBar_MinVelocityXToUnlock,2000) ;
mMinDistanceToUnlock = a.getInt(R.styleable.SlideBar_MinDistanceToUnlock,300) ;
mLeftAnimationDuration = a.getInt(R.styleable.SlideBar_LeftAnimationDuratioin,250) ;
mRightAnimationDuration = a.getInt(R.styleable.SlideBar_RightAnimationDuratioin,300) ;
a.recycle();
}
@Override
public boolean onTouchEvent(MotionEvent event) {
final int action = event.getActionMasked();
boolean handled = false;
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
}
mVelocityTracker.addMovement(event);
switch (action) {
case MotionEvent.ACTION_POINTER_DOWN:
case MotionEvent.ACTION_DOWN:
if (DEBUG) Log.v(TAG, "*** DOWN ***");
handleDown(event);
handled = true;
break;
case MotionEvent.ACTION_MOVE:
if (DEBUG) Log.v(TAG, "*** MOVE ***");
handleMove(event);
handled = true;
break;
case MotionEvent.ACTION_POINTER_UP:
case MotionEvent.ACTION_UP:
if (DEBUG) Log.v(TAG, "*** UP ***");
handleUp(event);
handled = true;
break;
case MotionEvent.ACTION_CANCEL:
if (DEBUG) Log.v(TAG, "*** CANCEL ***");
handled = true;
break;
}
invalidate();
return handled ? true : super.onTouchEvent(event);
}
public void handleUp(MotionEvent event) {
Log.v(TAG, "handleUp,mIndicateLeft:" + mGradientViewIndicateLeft);
//1. 如果用户滑动一些距离,解锁
if(mGradientViewIndicateLeft >= mMinDistanceToUnlock){
unlockSuccess();
return;
}
//2. 如果用户滑动很快,解锁
if(velocityTrigUnlock()){
return;
}
resetControls();
}
/** * 另一种方式来解锁,如果用户滑动非常快 */
private boolean velocityTrigUnlock() {
final VelocityTracker velocityTracker = mVelocityTracker;
velocityTracker.computeCurrentVelocity(1000);
int velocityX = (int) velocityTracker.getXVelocity();
Log.v(TAG, "velocityX:" + velocityX);
if(velocityX > mMinVelocityXToUnlock){
unlockSuccess();
return true;
}
if (mVelocityTracker != null) {
mVelocityTracker.recycle();
mVelocityTracker = null;
}
return false;
}
private void unlockSuccess() {
mOnTriggerListener.onTrigger();
animRightMoveAnimator = ObjectAnimator.ofFloat(mGradientView, "x",mGradientView.getX(), MaxDistance)
.setDuration(mRightAnimationDuration);
animRightMoveAnimator.start();
}
private void handleMove(MotionEvent event) {
mGradientViewIndicateLeft = event.getX() - mEventDownX + gradientViewStartX;
if(mGradientViewIndicateLeft <= gradientViewStartX){
mGradientViewIndicateLeft = gradientViewStartX;
}
mGradientView.setX(mGradientViewIndicateLeft);
}
private void handleDown(MotionEvent event) {
mEventDownX = event.getX();
if(mGradientView == null){
mGradientView = (GradientView) findViewById(R.id.gradientView);
}
mGradientView.stopAnimatorAndChangeColor();
}
public void setOnTriggerListener(OnTriggerListener listener) {
mOnTriggerListener = listener;
}
private void resetControls(){
mGradientView.startAnimator();
animLeftMoveAnimator = ObjectAnimator.ofFloat(mGradientView, "x", mGradientView.getX(),gradientViewStartX).setDuration(mLeftAnimationDuration);
animLeftMoveAnimator.start();
}
}
attrs:
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="IconEditText">
<attr name="iconSrc" format="reference" />
<attr name="isPassword" format="boolean" />
<attr name="hint" format="string"/>
</declare-styleable>
<declare-styleable name="GradientView">
<attr name="StringToShow" format="reference"/>
<attr name="TextSize" format="dimension"/>
<attr name="TextColor" format="integer"/>
<attr name="SlideColor" format="integer"/>
</declare-styleable>
<declare-styleable name="SlideBar">
<attr name="MinVelocityXToUnlock" format="integer"/>
<attr name="MinDistanceToUnlock" format="integer"/>
<attr name="LeftAnimationDuratioin" format="integer"/>
<attr name="RightAnimationDuratioin" format="integer"/>
</declare-styleable>
</resources>
源码地址:http://download.csdn.net/detail/ddwhan0123/9143841