Android滑動解鎖分享自定義組件

先看下滑動的效果圖? 滑動解鎖分享的一個(gè)效果

https://github.com/TangfeiJi/SlideToUnlockProject? ?源碼



我是以模塊的方式導(dǎo)入的??聪虏僮鞯牟襟E

1.下載模塊并導(dǎo)入在項(xiàng)目中。


2.在項(xiàng)目的Gradle中增加依賴


3.在布局中增加組件

<com.qdong.slide_to_unlock_view.CustomSlideToUnlockView

? ? ? ? android:id="@+id/slide_to_unlock"

? ? ? ? android:layout_width="match_parent"

? ? ? ? android:layout_height="44dp"

? ? ? ? android:layout_marginLeft="45dp"

? ? ? ? android:layout_marginTop="50dp"

? ? ? ? android:layout_marginRight="45dp"

? ? ? ? android:layout_marginBottom="40dp"

? ? ? ? chuck:slideImageViewResId="@mipmap/unlock_hide"

? ? ? ? chuck:slideImageViewResIdAfter="@mipmap/unlock_1_hide"

? ? ? ? chuck:slideImageViewWidth="35dp"

? ? ? ? chuck:slideThreshold="0.5"

? ? ? ? chuck:textColorResId="#fff"

? ? ? ? chuck:textHint="滑動解鎖"

? ? ? ? chuck:textSize="6"

? ? ? ? chuck:viewBackgroundResId="@drawable/shape_round_normal_green"

? ? ? ? tools:ignore="MissingConstraints">

? ? </com.qdong.slide_to_unlock_view.CustomSlideToUnlockView>

4.在activity中初始化并使用 這是列出它給出的監(jiān)聽

? ? CustomSlideToUnlockView.CallBack callBack = new CustomSlideToUnlockView.CallBack() {

? ? ? ? ? ? @Override//滑動到的位置

? ? ? ? ? ? public void onSlide(int distance) {

? ? ? ? ? ? ? ? Log.e("1111",distance+"");

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onUnlocked() {? //滑動到最后解鎖

? ? ? ? ? ? ? ? pop_layout.setVisibility(View.VISIBLE);

? ? ? ? ? ? ? ? Toast.makeText(MainActivity.this,"onUnlocked",Toast.LENGTH_LONG).show();

? ? ? ? ? ? }

? ? ? ? };

來看看源碼我這已經(jīng)給出了注釋說明

package com.qdong.slide_to_unlock_view;

import android.content.Context;

import android.content.res.TypedArray;

import android.text.TextUtils;

import android.util.AttributeSet;

import android.util.Log;

import android.view.LayoutInflater;

import android.view.MotionEvent;

import android.view.View;

import android.view.animation.AccelerateInterpolator;

import android.widget.ImageView;

import android.widget.RelativeLayout;

import android.widget.TextView;

import com.github.florent37.viewanimator.AnimationListener;

import com.github.florent37.viewanimator.ViewAnimator;

import com.nineoldandroids.view.ViewHelper;

/**

**/

public class CustomSlideToUnlockView extends RelativeLayout {

? ? private static final String TAG="CustomSlideToUnlockView";

? ? private static final long DEAFULT_DURATIN_LONG = 200;//左彈回,動畫時(shí)長

? ? private static final long DEAFULT_DURATIN_SHORT = 100;//右彈,動畫時(shí)長

? ? private static final boolean LOG = true;//打印開關(guān)

? ? private static int? DISTANCE_LIMIT = 600;//滑動閾值

? ? private static float? THRESHOLD = 0.5F;//滑動閾值比例:默認(rèn)是0.5,即滑動超過父容器寬度的一半再松手就會觸發(fā)

? ? protected Context mContext;

? ? private ImageView iv_slide;//滑塊

? ? private TextView tv_hint;//提示文本

? ? private RelativeLayout rl_slide;//滑動view

? ? private RelativeLayout rl_root;//父容器

? ? private boolean mIsUnLocked;//已經(jīng)滑到最右邊,將不再響應(yīng)touch事件

? ? private CallBack mCallBack;//回調(diào)

? ? private int slideImageViewWidth;//滑塊寬度

? ? private int? slideImageViewResId;//滑塊資源

? ? private int? slideImageViewResIdAfter;//滑動到右邊時(shí),滑塊資源id

? ? private int? viewBackgroundResId;//root 背景

? ? private String textHint;//文本

? ? private int textSize;//單位是sp,只拿數(shù)值

? ? private int textColorResId;//顏色,@color

? ? public CustomSlideToUnlockView(Context mContext) {

? ? ? ? super(mContext);

? ? ? ? this.mContext = mContext;

? ? ? ? initView();

? ? }

? ? public CustomSlideToUnlockView(Context mContext, AttributeSet attrs) {

? ? ? ? super(mContext, attrs);

? ? ? ? this.mContext = mContext;

? ? ? ? TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs,

? ? ? ? ? ? ? ? R.styleable.SlideToUnlockView);

? ? ? ? init(mTypedArray);

? ? ? ? initView();

? ? }

? ? public CustomSlideToUnlockView(Context mContext, AttributeSet attrs, int defStyleAttr) {

? ? ? ? super(mContext, attrs, defStyleAttr);

? ? ? ? this.mContext = mContext;

? ? ? ? TypedArray mTypedArray = mContext.obtainStyledAttributes(attrs,

? ? ? ? ? ? ? ? R.styleable.SlideToUnlockView);

? ? ? ? init(mTypedArray);

? ? ? ? initView();

? ? }

? ? /**

? ? **/

? ? private void init(TypedArray mTypedArray) {

? ? ? ? slideImageViewWidth= (int) mTypedArray.getDimension(R.styleable.SlideToUnlockView_slideImageViewWidth, DensityUtil.dp2px(getContext(), 50));

? ? ? ? slideImageViewResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResId, -1);

? ? ? ? slideImageViewResIdAfter= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_slideImageViewResIdAfter, -1);

? ? ? ? viewBackgroundResId= mTypedArray.getResourceId(R.styleable.SlideToUnlockView_viewBackgroundResId, -1);

? ? ? ? textHint=mTypedArray.getString(R.styleable.SlideToUnlockView_textHint);

? ? ? ? textSize=mTypedArray.getInteger(R.styleable.SlideToUnlockView_textSize, 7);

? ? ? ? textColorResId= mTypedArray.getColor(R.styleable.SlideToUnlockView_textColorResId, getResources().getColor(android.R.color.white));

? ? ? ? THRESHOLD=mTypedArray.getFloat(R.styleable.SlideToUnlockView_slideThreshold, 0.5f);

? ? ? ? mTypedArray.recycle();

? ? }

? ? private int mActionDownX, mLastX, mSlidedDistance;

? ? /**

? ? * 初始化界面布局

? ? */

? ? protected void initView() {

? ? ? ? LayoutInflater.from(mContext).inflate(R.layout.layout_view_slide_to_unlock,

? ? ? ? ? ? ? ? this, true);

? ? ? ? rl_root = (RelativeLayout) findViewById(R.id.rl_root);

? ? ? ? rl_slide = (RelativeLayout) findViewById(R.id.rl_slide);

? ? ? ? iv_slide = (ImageView) findViewById(R.id.iv_slide);

? ? ? ? tv_hint = (TextView) findViewById(R.id.tv_hint);

? ? ? ? LayoutParams params= (LayoutParams) iv_slide .getLayoutParams();

? ? ? ? //獲取當(dāng)前控件的布局對象

? ? ? ? params.width= slideImageViewWidth;//設(shè)置當(dāng)前控件布局的高度

? ? ? ? iv_slide.setLayoutParams(params);//將設(shè)置好的布局參數(shù)應(yīng)用到控件中

? ? ? ? setImageDefault();

? ? ? ? if(viewBackgroundResId>0){

//? ? ? ? ? ? rl_slide.setBackgroundResource(viewBackgroundResId);//rootView設(shè)置背景

? ? ? ? }

? ? ? ? MarginLayoutParams tvParams = (MarginLayoutParams) tv_hint.getLayoutParams();

? ? ? ? tvParams.setMargins(0, 0, slideImageViewWidth, 0);//textview的marginRight設(shè)置為和滑塊的寬度一致

? ? ? ? tv_hint.setLayoutParams(tvParams);

? ? ? ? tv_hint.setTextSize(DensityUtil.sp2px(getContext(), textSize));

? ? ? ? tv_hint.setTextColor(textColorResId);

? ? ? ? tv_hint.setText(TextUtils.isEmpty(textHint)? mContext.getString(R.string.hint):textHint);

? ? ? ? //添加滑動監(jiān)聽

? ? ? ? rl_slide.setOnTouchListener(new OnTouchListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public boolean onTouch(View v, MotionEvent event) {

? ? ? ? ? ? ? ? DISTANCE_LIMIT= (int) (CustomSlideToUnlockView.this.getWidth()*THRESHOLD);//默認(rèn)閾值是控件寬度的一半

? ? ? ? ? ? ? ? switch (event.getAction()) {

? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_DOWN://按下時(shí)記錄縱坐標(biāo)

? ? ? ? ? ? ? ? ? ? ? ? if(mIsUnLocked){//滑塊已經(jīng)在最右邊則不處理touch

? ? ? ? ? ? ? ? ? ? ? ? ? ? return false;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? mLastX = (int) event.getRawX();//最后一個(gè)action時(shí)x值

? ? ? ? ? ? ? ? ? ? ? ? mActionDownX = (int) event.getRawX();//按下的瞬間x

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, mLastX + "X,=============================ACTION_DOWN");

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_MOVE://上滑才處理,如果用戶一開始就下滑,則過掉不處理

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "=============================ACTION_MOVE");

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "event.getRawX()============================="+event.getRawX());

? ? ? ? ? ? ? ? ? ? ? ? int dX = (int) event.getRawX() - mLastX;

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "dX============================="+dX);

? ? ? ? ? ? ? ? ? ? ? ? mSlidedDistance = (int) event.getRawX() - mActionDownX;

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "mSlidedDistance============================="+ mSlidedDistance);

? ? ? ? ? ? ? ? ? ? ? ? final MarginLayoutParams params = (MarginLayoutParams) v.getLayoutParams();

? ? ? ? ? ? ? ? ? ? ? ? int left = params.leftMargin;

? ? ? ? ? ? ? ? ? ? ? ? int top = params.topMargin;

? ? ? ? ? ? ? ? ? ? ? ? int right = params.rightMargin;

? ? ? ? ? ? ? ? ? ? ? ? int bottom = params.bottomMargin;

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "left:"+left+",top:"+top+",right:"+right+",bottom"+bottom);

? ? ? ? ? ? ? ? ? ? ? ? int leftNew = left + dX;

? ? ? ? ? ? ? ? ? ? ? ? int rightNew =right - dX;

? ? ? ? ? ? ? ? ? ? ? ? if (mSlidedDistance > 0) {//直接通過margin實(shí)現(xiàn)滑動

? ? ? ? ? ? ? ? ? ? ? ? ? ? params.setMargins(leftNew, top, rightNew, bottom);

? ? ? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, leftNew + "=============================MOVE");

? ? ? ? ? ? ? ? ? ? ? ? ? ? v.setLayoutParams(params);

? ? ? ? ? ? ? ? ? ? ? ? ? ? resetTextViewAlpha(mSlidedDistance);

? ? ? ? ? ? ? ? ? ? ? ? ? ? //回調(diào)

? ? ? ? ? ? ? ? ? ? ? ? ? ? if(mCallBack!=null){

? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? mCallBack.onSlide(mSlidedDistance);

? ? ? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? ? ? mLastX = (int) event.getRawX();

? ? ? ? ? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_UP:

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "MotionEvent.ACTION_UP,之前移動的偏移值:" + ViewHelper.getTranslationY(v));

? ? ? ? ? ? ? ? ? ? ? ? if (Math.abs(mSlidedDistance) > DISTANCE_LIMIT) {

? ? ? ? ? ? ? ? ? ? ? ? ? ? scrollToRight(v);//右邊

//? ? ? ? ? ? ? ? ? ? ? ? ? ? scrollToLeft(v);//左邊

? ? ? ? ? ? ? ? ? ? ? ? } else {

? ? ? ? ? ? ? ? ? ? ? ? ? ? scrollToLeft(v);//左邊

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? ? ? case MotionEvent.ACTION_CANCEL:

//? ? ? ? ? ? ? ? ? ? ? ? try {

//? ? ? ? ? ? ? ? ? ? ? ? ? ? if (vTracker != null) {

//? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? vTracker.recycle();

//? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? vTracker = null;

//? ? ? ? ? ? ? ? ? ? ? ? ? ? }

//? ? ? ? ? ? ? ? ? ? ? ? ? ? vTracker.recycle();

//? ? ? ? ? ? ? ? ? ? ? ? } catch (Exception e) {

//? ? ? ? ? ? ? ? ? ? ? ? ? ? e.printStackTrace();

//? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? break;

? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? return true;

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? private void logI(String tag,String content){

? ? ? ? if(LOG){

? ? ? ? ? ? Log.i(tag,content);

? ? ? ? }

? ? }

? ? /**

? ? * @method name:resetTextViewAlpha

? ? * @des:? 重置提示文本的透明度

? ? * @param :[mSlidedDistance]

? ? * @return type:void

? ? * @date 創(chuàng)建時(shí)間:2017/5/24

? ? * @author Chuck

? ? **/

? ? private void resetTextViewAlpha(int distance) {

? ? ? ? if(Math.abs(distance)>=Math.abs(DISTANCE_LIMIT)){

? ? ? ? ? ? tv_hint.setAlpha(0.0f);

? ? ? ? }

? ? ? ? else{

? ? ? ? ? ? tv_hint.setAlpha(1.0f-Math.abs(distance)*1.0f/Math.abs(DISTANCE_LIMIT));

? ? ? ? }

? ? }

? ? /**

? ? * @method name:scrollToLeft

? ? * @des:? 滑動未到閾值時(shí)松開手指,彈回到最左邊

? ? * @param :[v]

? ? * @return type:void

? ? * @date 創(chuàng)建時(shí)間:2017/5/24

? ? * @author Chuck

? ? **/

? ? private void scrollToLeft(final View v) {

? ? ? ? final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams();

? ? ? ? logI(TAG, "scrollToLeft,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v));

? ? ? ? logI(TAG, "scrollToLeft,params1.leftMargin:" + params1.leftMargin);

? ? ? ? logI(TAG, "scrollToLeft, params1.rightMargin:" + params1.rightMargin);

? ? ? ? ViewAnimator

? ? ? ? ? ? ? ? .animate( rl_slide)

? ? ? ? ? ? ? ? .translationX(ViewHelper.getTranslationX(v), -params1.leftMargin+15)

? ? ? ? ? ? ? ? .interpolator(new AccelerateInterpolator())

? ? ? ? ? ? ? ? .duration(DEAFULT_DURATIN_LONG)

? ? ? ? ? ? ? ? .onStop(new AnimationListener.Stop() {

? ? ? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? ? ? public void onStop() {

? ? ? ? ? ? ? ? ? ? ? ? MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams();

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToLeft動畫結(jié)束para.leftMargin:" + para.leftMargin);

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToLeft動畫結(jié)束para.rightMargin:" + para.rightMargin);

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToLeft動畫結(jié)束,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v));

? ? ? ? ? ? ? ? ? ? ? ? mSlidedDistance = 0;

? ? ? ? ? ? ? ? ? ? ? ? tv_hint.setAlpha(1.0f);

? ? ? ? ? ? ? ? ? ? ? ? mIsUnLocked=false;

? ? ? ? ? ? ? ? ? ? ? ? if(mCallBack!=null){

? ? ? ? ? ? ? ? ? ? ? ? ? ? mCallBack.onSlide(mSlidedDistance);

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? setImageDefault();

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? })

? ? ? ? ? ? ? ? .start();

? ? }

? ? /**


? ? **/

? ? private void scrollToRight(final View v) {

? ? ? ? final MarginLayoutParams params1 = (MarginLayoutParams) v.getLayoutParams();

? ? ? ? logI(TAG, "scrollToRight,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v));

? ? ? ? logI(TAG, "scrollToRight,params1.leftMargin:" + params1.leftMargin);

? ? ? ? logI(TAG, "scrollToRight, params1.rightMargin:" + params1.rightMargin);

? ? ? ? //移動到最右端? 移動的距離是 父容器寬度-leftMargin

? ? ? ? ViewAnimator

? ? ? ? ? ? ? ? .animate( rl_slide)

? ? ? ? ? ? ? ? //.translationX(ViewHelper.getTranslationX(v), ViewHelper.getTranslationX(v)+100)

? ? ? ? ? ? ? ? .translationX(ViewHelper.getTranslationX(v), -params1.leftMargin+15)

//? ? ? ? ? ? ? ? .translationX(ViewHelper.getTranslationX(v), ( rl_slide.getWidth() - params1.leftMargin-slideImageViewWidth))

? ? ? ? ? ? ? ? //.translationX(params1.leftMargin, ( rl_slide.getWidth() - params1.leftMargin-100))

? ? ? ? ? ? ? ? .interpolator(new AccelerateInterpolator())

? ? ? ? ? ? ? ? .duration(DEAFULT_DURATIN_SHORT)

? ? ? ? ? ? ? ? .onStop(new AnimationListener.Stop() {

? ? ? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? ? ? public void onStop() {

? ? ? ? ? ? ? ? ? ? ? ? MarginLayoutParams para = (MarginLayoutParams) v.getLayoutParams();

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToRight動畫結(jié)束para.leftMargin:" + para.leftMargin);

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToRight動畫結(jié)束para.rightMargin:" + para.rightMargin);

? ? ? ? ? ? ? ? ? ? ? ? logI(TAG, "scrollToRight動畫結(jié)束,ViewHelper.getTranslationX(v):" + ViewHelper.getTranslationX(v));

? ? ? ? ? ? ? ? ? ? ? ? mSlidedDistance = 0;

? ? ? ? ? ? ? ? ? ? ? ? tv_hint.setAlpha(1.0f);

? ? ? ? ? ? ? ? ? ? ? ? mIsUnLocked=false;

//? ? ? ? ? ? ? ? ? ? ? ? if(slideImageViewResIdAfter>0){

//? ? ? ? ? ? ? ? ? ? ? ? ? ? iv_slide.setImageResource(slideImageViewResIdAfter);//滑塊imagview設(shè)置資源

//? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? ? ? //回調(diào)

? ? ? ? ? ? ? ? ? ? ? ? if(mCallBack!=null){

? ? ? ? ? ? ? ? ? ? ? ? ? ? mCallBack.onUnlocked();

? ? ? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? ? ? }

? ? ? ? ? ? ? ? })

? ? ? ? ? ? ? ? .start();

? ? }

? ? public void resetView(){

? ? ? ? mIsUnLocked=false;

? ? ? ? setImageDefault();

? ? ? ? scrollToLeft(rl_slide);

? ? }

? ? private void setImageDefault() {

? ? ? ? /**


? ? ? ? **/

? ? ? ? if(slideImageViewResId>0){

? ? ? ? ? ? iv_slide.setImageResource(slideImageViewResId);//滑塊imagview設(shè)置資源

? ? ? ? }

? ? }

? ? public interface CallBack{

? ? ? ? void onSlide(int distance);//右滑距離回調(diào)

? ? ? ? void onUnlocked();//滑動到了右邊,事件回調(diào)

? ? }

? ? public CallBack getmCallBack() {

? ? ? ? return mCallBack;

? ? }

? ? public void setmCallBack(CallBack mCallBack) {

? ? ? ? this.mCallBack = mCallBack;

? ? }

}


————————————————

版權(quán)聲明:本文為CSDN博主「weixin_36495794」的原創(chuàng)文章,遵循 CC 4.0 BY-SA 版權(quán)協(xié)議,轉(zhuǎn)載請附上原文出處鏈接及本聲明。

原文鏈接:https://blog.csdn.net/weixin_36495794/article/details/102517617

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容