android滑動拼圖驗證碼控件


滑動拼圖驗證碼一般我們在網(wǎng)站上可以經(jīng)常見到,本篇文章給大家介紹該效果在android端的是如何實現(xiàn)

首先看一下效果圖:


* 新建自定義view DragImageView主要方法:

* 設(shè)置圖片宪迟、滑塊資源穿仪,設(shè)置圖片意荤、滑塊之間的比例大小

* 滑塊滑到正確位置紫谷,拼圖成功調(diào)用ok()方法

* 滑塊滑動位置錯誤笤昨,拼圖失敗調(diào)用fail()方法

* 重新滑動,reset()方法

* 拼圖成功后崇裁,圖片一道閃亮效果

* 整個類代碼如下:

package com.yolanda.code.library.widget;

import android.animation.ValueAnimator;

import android.content.Context;

import android.graphics.Bitmap;

import android.os.Handler;

import android.util.AttributeSet;

import android.view.View;

import android.view.ViewGroup;

import android.view.animation.AlphaAnimation;

import android.view.animation.Animation;

import android.view.animation.LinearInterpolator;

import android.view.animation.TranslateAnimation;

import android.widget.FrameLayout;

import android.widget.ImageView;

import android.widget.SeekBar;

import android.widget.TextView;

import com.yolanda.code.library.R;

import com.yolanda.code.library.view.DiyStyleTextView;

/**

* @author Created by Yolanda on 2018/10/31.

* @description 滑動拼圖驗證碼

*/

public final class DragImageView extends FrameLayout implements SeekBar.OnSeekBarChangeListener {

? ? private final int showTipsTime = 1500;

? ? private final int animeTime = 333;

? ? private final int flashTime = 800;

? ? private ImageView ivCover;

? ? private ImageView ivBlock;

? ? private SeekBar sb;

? ? private TextView tvTips2;

? ? private DiyStyleTextView tvTips;

? ? private View vFlash, flContent;

? ? private Handler handler = new Handler();

? ? private Bitmap cover, block, completeCover;

? ? private boolean isNormal;

? ? public DragImageView(Context context) {

? ? ? ? super(context);

? ? ? ? init();

? ? }

? ? public DragImageView(Context context, AttributeSet attrs) {

? ? ? ? super(context, attrs);

? ? ? ? init();

? ? }

? ? public DragImageView(Context context, AttributeSet attrs, int defStyle) {

? ? ? ? super(context, attrs, defStyle);

? ? ? ? init();

? ? }

? ? private void init() {

? ? ? ? View.inflate(getContext(), R.layout.drag_view, this);

? ? ? ? flContent = findViewById(R.id.drag_fl_content);

? ? ? ? ivCover = findViewById(R.id.drag_iv_cover);

? ? ? ? ivBlock = findViewById(R.id.drag_iv_block);

? ? ? ? tvTips = findViewById(R.id.drag_tv_tips);

? ? ? ? tvTips2 = findViewById(R.id.drag_tv_tips2);

? ? ? ? vFlash = findViewById(R.id.drag_v_flash);

? ? ? ? tvTips.setColorRegex("拼圖|成功|失敗|正確|[\\d\\.%]+", 0xfff75151);

? ? ? ? sb = findViewById(R.id.drag_sb);

? ? ? ? sb.setMax(getContext().getResources().getDisplayMetrics().widthPixels);

? ? ? ? sb.setOnSeekBarChangeListener(this);

? ? ? ? reset();

? ? }

? ? /**

? ? * 設(shè)置資源

? ? *

? ? * @param cover? ? ? ? 拼圖

? ? * @param block? ? ? ? 滑塊

? ? * @param completeCover 完成的拼圖

? ? * @param block_y? ? ? 滑塊Y值比例

? ? */

? ? public void setUp(Bitmap cover, Bitmap block, Bitmap completeCover, float block_y) {

? ? ? ? this.cover = cover;

? ? ? ? this.block = block;

? ? ? ? this.completeCover = completeCover;

? ? ? ? ivCover.setImageBitmap(completeCover);

? ? ? ? ivBlock.setImageBitmap(block);

? ? ? ? setLocation(1f * cover.getWidth() / cover.getHeight(), 1f * block.getHeight() / cover.getHeight(), block_y);

? ? }

? ? /**

? ? * 設(shè)置比例大小

? ? *

? ? * @param cover_wph? 圖片bili

? ? * @param block_size 滑塊大小占高比

? ? * @param block_y? ? 滑塊位置占高比

? ? */

? ? private void setLocation(final float cover_wph, final float block_size, final float block_y) {

? ? ? ? post(new Runnable() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void run() {

? ? ? ? ? ? ? ? final int w = flContent.getMeasuredWidth();

? ? ? ? ? ? ? ? int h = (int) (w / cover_wph);

? ? ? ? ? ? ? ? ViewGroup.LayoutParams l = flContent.getLayoutParams();

? ? ? ? ? ? ? ? l.width = w;

? ? ? ? ? ? ? ? l.height = h;

? ? ? ? ? ? ? ? flContent.setLayoutParams(l);

? ? ? ? ? ? ? ? ViewGroup.MarginLayoutParams l2 = (MarginLayoutParams) ivBlock.getLayoutParams();

? ? ? ? ? ? ? ? l2.height = (int) (h * block_size);

? ? ? ? ? ? ? ? l2.width = l2.height * block.getWidth() / block.getHeight();

? ? ? ? ? ? ? ? l2.topMargin = (int) (h * block_y);

? ? ? ? ? ? ? ? ivBlock.setLayoutParams(l2);

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? public void ok() {

? ? ? ? ivCover.setImageBitmap(completeCover);

? ? ? ? blockHideAnime();

? ? ? ? int penset = (int) (99 - (timeUse > 1 ? timeUse - 1 : 0) / 0.1f);

? ? ? ? if (penset < 1) penset = 1;

? ? ? ? tvTips.setText(String.format("拼圖成功: 耗時%.1f秒,打敗了%d%%的用戶!", timeUse, penset));

? ? ? ? tipsShowAnime(true);

? ? ? ? flashShowAnime();

? ? ? ? sb.setEnabled(false);

? ? }

? ? public void fail() {

? ? ? ? twinkleImage(ivBlock);

? ? ? ? tvTips.setText("拼圖失敗: 請重新拖曳滑塊到正確的位置!");

? ? ? ? tipsShowAnime(true);

? ? ? ? handler.postDelayed(resetRun, showTipsTime);

? ? ? ? sb.setEnabled(false);

? ? }

? ? public void reset() {

? ? ? ? final int position = sb.getProgress();

? ? ? ? if (position != 0) {

? ? ? ? ? ? ValueAnimator animator = ValueAnimator.ofFloat(1f, 0);

? ? ? ? ? ? animator.setDuration(animeTime).start();

? ? ? ? ? ? animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator animation) {

? ? ? ? ? ? ? ? ? ? float f = (Float) animation.getAnimatedValue();

? ? ? ? ? ? ? ? ? ? sb.setProgress((int) (position * f));

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? }

? ? ? ? tipsShowAnime(false);

? ? ? ? tips2ShowAnime(true);

? ? ? ? sb.setEnabled(true);

? ? ? ? ivBlock.setVisibility(GONE);

? ? ? ? vFlash.setVisibility(GONE);

? ? ? ? ivCover.setImageBitmap(completeCover);

? ? ? ? isNormal = true;

? ? }

? ? //===================seekbar監(jiān)聽===================

? ? private long timeTemp;

? ? private float timeUse;

? ? @Override

? ? public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) {

? ? ? ? int cw = ivCover.getMeasuredWidth();

? ? ? ? int bw = ivBlock.getMeasuredWidth();

? ? ? ? ViewGroup.MarginLayoutParams l = (MarginLayoutParams) ivBlock.getLayoutParams();

? ? ? ? l.leftMargin = (cw - bw) * progress / seekBar.getMax();

? ? ? ? ivBlock.setLayoutParams(l);

? ? }

? ? @Override

? ? public void onStartTrackingTouch(SeekBar seekBar) {

? ? ? ? ivBlock.setVisibility(VISIBLE);

? ? ? ? ivCover.setImageBitmap(cover);

? ? ? ? tips2ShowAnime(false);

? ? ? ? timeTemp = System.currentTimeMillis();

? ? ? ? isNormal = false;

? ? }

? ? @Override

? ? public void onStopTrackingTouch(SeekBar seekBar) {

? ? ? ? timeUse = (System.currentTimeMillis() - timeTemp) / 1000.f;

? ? ? ? if (dragListenner != null)

? ? ? ? ? ? dragListenner.onDrag(seekBar.getProgress() * 1f / seekBar.getMax());

? ? }

? ? //===================seekbar監(jiān)聽===================

? ? //閃爍滑塊

? ? private void twinkleImage(final View view) {

? ? ? ? ValueAnimator animator = ValueAnimator.ofFloat(0, 1.0F);

? ? ? ? animator.setTarget(view);

? ? ? ? animator.setInterpolator(new LinearInterpolator());

? ? ? ? animator.setDuration(showTipsTime).start();

? ? ? ? animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator animation) {

? ? ? ? ? ? ? ? float f = (Float) animation.getAnimatedValue();

? ? ? ? ? ? ? ? int time = (int) (showTipsTime * f);

? ? ? ? ? ? ? ? if (time < 125)

? ? ? ? ? ? ? ? ? ? view.setVisibility(INVISIBLE);

? ? ? ? ? ? ? ? else if (time < 250)

? ? ? ? ? ? ? ? ? ? view.setVisibility(VISIBLE);

? ? ? ? ? ? ? ? else if (time < 375)

? ? ? ? ? ? ? ? ? ? view.setVisibility(INVISIBLE);

? ? ? ? ? ? ? ? else

? ? ? ? ? ? ? ? ? ? view.setVisibility(VISIBLE);

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? //提示文本顯示隱藏

? ? private void tipsShowAnime(boolean isShow) {

? ? ? ? if ((tvTips.getVisibility() == VISIBLE) == isShow)

? ? ? ? ? ? return;

? ? ? ? TranslateAnimation translateAnimation = new TranslateAnimation(

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, 0f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, 0f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, isShow ? 1f : 0f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, isShow ? 0f : 1f);

? ? ? ? translateAnimation.setDuration(animeTime);

? ? ? ? //translateAnimation.setInterpolator(new LinearInterpolator());

? ? ? ? tvTips.setAnimation(translateAnimation);

? ? ? ? tvTips.setVisibility(isShow ? VISIBLE : GONE);

? ? }

? ? //提示文本顯示隱藏

? ? private void tips2ShowAnime(boolean isShow) {

? ? ? ? if ((tvTips2.getVisibility() == VISIBLE) == isShow)

? ? ? ? ? ? return;

? ? ? ? AlphaAnimation translateAnimation = new AlphaAnimation(isShow ? 0 : 1, isShow ? 1 : 0);

? ? ? ? translateAnimation.setDuration(animeTime);

? ? ? ? //translateAnimation.setInterpolator(new LinearInterpolator());

? ? ? ? tvTips2.setAnimation(translateAnimation);

? ? ? ? tvTips2.setVisibility(isShow ? VISIBLE : GONE);

? ? }

? ? //成功完成拼圖滑塊消失

? ? private void blockHideAnime() {

? ? ? ? AlphaAnimation translateAnimation = new AlphaAnimation(1, 0);

? ? ? ? translateAnimation.setDuration(animeTime);

? ? ? ? //translateAnimation.setInterpolator(new LinearInterpolator());

? ? ? ? ivBlock.setAnimation(translateAnimation);

? ? ? ? ivBlock.setVisibility(GONE);

? ? }

? ? //失敗震動動畫

? ? private void failAnime() {

? ? }

? ? //成功高亮動畫

? ? private void flashShowAnime() {

? ? ? ? TranslateAnimation translateAnimation = new TranslateAnimation(

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, 1f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, -1f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, 0f,

? ? ? ? ? ? ? ? Animation.RELATIVE_TO_SELF, 0f);

? ? ? ? translateAnimation.setDuration(flashTime);

? ? ? ? //translateAnimation.setInterpolator(new LinearInterpolator());

? ? ? ? vFlash.setAnimation(translateAnimation);

? ? ? ? vFlash.setVisibility(VISIBLE);

? ? ? ? translateAnimation.setAnimationListener(new Animation.AnimationListener() {

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onAnimationStart(Animation animation) {

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onAnimationEnd(Animation animation) {

? ? ? ? ? ? ? ? vFlash.setVisibility(GONE);

? ? ? ? ? ? }

? ? ? ? ? ? @Override

? ? ? ? ? ? public void onAnimationRepeat(Animation animation) {

? ? ? ? ? ? }

? ? ? ? });

? ? }

? ? //失敗延時重置控件

? ? private Runnable resetRun = new Runnable() {

? ? ? ? @Override

? ? ? ? public void run() {

? ? ? ? ? ? tipsShowAnime(false);

? ? ? ? ? ? tips2ShowAnime(true);

? ? ? ? ? ? sb.setEnabled(true);

? ? ? ? ? ? final int position = sb.getProgress();

? ? ? ? ? ? ValueAnimator animator = ValueAnimator.ofFloat(1f, 0);

? ? ? ? ? ? animator.setDuration(animeTime).start();

? ? ? ? ? ? animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {

? ? ? ? ? ? ? ? @Override

? ? ? ? ? ? ? ? public void onAnimationUpdate(ValueAnimator animation) {

? ? ? ? ? ? ? ? ? ? float f = (Float) animation.getAnimatedValue();

? ? ? ? ? ? ? ? ? ? sb.setProgress((int) (position * f));

? ? ? ? ? ? ? ? }

? ? ? ? ? ? });

? ? ? ? ? ? isNormal = true;

? ? ? ? }

? ? };

? ? //監(jiān)聽

? ? private DragListenner dragListenner;

? ? public interface DragListenner {

? ? ? ? void onDrag(float position);

? ? }

? ? public void setDragListenner(DragListenner dragListenner) {

? ? ? ? this.dragListenner = dragListenner;

? ? }

}

* 完整項目請前往:?項目github地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末挺庞,一起剝皮案震驚了整個濱河市选侨,隨后出現(xiàn)的幾起案子援制,更是在濱河造成了極大的恐慌芍瑞,老刑警劉巖晨仑,帶你破解...
    沈念sama閱讀 218,386評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異拆檬,居然都是意外死亡洪己,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,142評論 3 394
  • 文/潘曉璐 我一進(jìn)店門竟贯,熙熙樓的掌柜王于貴愁眉苦臉地迎上來答捕,“玉大人,你說我怎么就攤上這事屑那」案洌” “怎么了?”我有些...
    開封第一講書人閱讀 164,704評論 0 353
  • 文/不壞的土叔 我叫張陵持际,是天一觀的道長阵难。 經(jīng)常有香客問我朱庆,道長傲诵,這世上最難降的妖魔是什么剧罩? 我笑而不...
    開封第一講書人閱讀 58,702評論 1 294
  • 正文 為了忘掉前任啦鸣,我火速辦了婚禮蝙搔,結(jié)果婚禮上证鸥,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,716評論 6 392
  • 文/花漫 我一把揭開白布狂丝。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪准颓。 梳的紋絲不亂的頭發(fā)上样勃,一...
    開封第一講書人閱讀 51,573評論 1 305
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的望众。 我是一名探鬼主播蚤氏,決...
    沈念sama閱讀 40,314評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了蚌成?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,230評論 0 276
  • 序言:老撾萬榮一對情侶失蹤鹉勒,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后脯倒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體藻丢,經(jīng)...
    沈念sama閱讀 45,680評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡斋否,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,873評論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了追葡。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,991評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡填硕,死狀恐怖麦萤,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情扁眯,我是刑警寧澤壮莹,帶...
    沈念sama閱讀 35,706評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站姻檀,受9級特大地震影響命满,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜绣版,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,329評論 3 330
  • 文/蒙蒙 一胶台、第九天 我趴在偏房一處隱蔽的房頂上張望狭莱。 院中可真熱鬧,春花似錦概作、人聲如沸腋妙。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,910評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽骤素。三九已至,卻和暖如春愚屁,著一層夾襖步出監(jiān)牢的瞬間济竹,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,038評論 1 270
  • 我被黑心中介騙來泰國打工霎槐, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留送浊,地道東北人。 一個月前我還...
    沈念sama閱讀 48,158評論 3 370
  • 正文 我出身青樓丘跌,卻偏偏與公主長得像袭景,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子闭树,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,941評論 2 355

推薦閱讀更多精彩內(nèi)容