Android滑动拼图验证码控件使用方法详解
时间:2022-01-16 08:53:36|栏目:Android代码|点击: 次
简介: 很多软件为了安全防止恶意攻击,会在登录/注册时进行人机验证,常见的人机验证方式有:谷歌点击复选框进行验证,输入验证码验证,短信验证码,语音验证,文字按顺序选择在图片上点击,滑动拼图验证等。
效果图:
代码实现:
1、滑块视图类:SlideImageView.java。实现随机选取拼图位置,对拼图位置进行验证等功能。
public class SlideImageView extends View { Bitmap bitmap; Bitmap drawBitmap; Bitmap verifyBitmap; boolean reset = true; // 拼图的位置 int x; int y; // 验证的地方 int left, top, right, bottom; // 移动x坐标 int moveX; // x坐标最大移动长度 int moveMax; // 正确的拼图x坐标 int trueX; public SlideImageView(Context context) { super(context); } public SlideImageView(Context context, AttributeSet attrs) { super(context, attrs); } public SlideImageView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); if (bitmap == null) return; if (reset) { /* * 背景图 */ int width = getWidth(); int height = getHeight(); drawBitmap = Bitmap.createScaledBitmap(bitmap, width, height, false); /* * 验证的地方 */ int length = Math.min(width, height); length /= 4;//1/4长度 // 随机选取拼图的位置 x = new Random().nextInt(width - length * 2) + length; y = new Random().nextInt(height - length * 2) + length; left = x; top = y; right = left + length; bottom = top + length; //验证的图片 verifyBitmap = Bitmap.createBitmap(drawBitmap, x, y, length, length); // 验证图片的最大移动距离 moveMax = width - length; // 正确的验证位置x trueX = x; reset = false; } Paint paint = new Paint(); // 画背景图 canvas.drawBitmap(drawBitmap, 0, 0, paint); paint.setColor(Color.parseColor("#66000000")); canvas.drawRect(left, top, right, bottom, paint);//画上阴影 paint.setColor(Color.parseColor("#ffffffff")); canvas.drawBitmap(verifyBitmap, moveX, y, paint);//画验证图片 } public void setImageBitmap(Bitmap bitmap) { this.bitmap = bitmap; } public void setMove(double precent) { if (precent < 0 || precent > 1) return; moveX = (int) (moveMax * precent); invalidate(); } public boolean isTrue(double range) { if (moveX > trueX * (1 - range) && moveX < trueX * (1 + range)) { return true; } else { return false; } } public void setReDraw() { reset = true; invalidate(); } }
2、视图布局文件:activity_main.xml。
<?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.slideimage.MainActivity"> <com.slideimage.SlideImageView android:id="@+id/slide_image_view" android:layout_width="240dp" android:layout_height="150dp" android:layout_marginTop="50dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> <View android:id="@+id/flash_view" android:layout_width="wrap_content" android:layout_height="wrap_content" android:visibility="invisible" app:layout_constraintLeft_toLeftOf="@id/slide_image_view" app:layout_constraintRight_toRightOf="@id/slide_image_view" app:layout_constraintTop_toTopOf="@id/slide_image_view" app:layout_constraintBottom_toBottomOf="@id/slide_image_view" android:background="@mipmap/drag_flash"/> <SeekBar android:id="@+id/seekBar1" android:layout_width="240dp" android:layout_height="wrap_content" android:layout_marginTop="220dp" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> <TextView android:id="@+id/show_result" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="280dp" android:textSize="20sp" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent" app:layout_constraintTop_toTopOf="parent"/> <Button android:id="@+id/button1" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="320dp" android:text="重新初始化" app:layout_constraintTop_toTopOf="parent" app:layout_constraintLeft_toLeftOf="parent" app:layout_constraintRight_toRightOf="parent"/> </android.support.constraint.ConstraintLayout>
3、在Activity中使用滑块验证:MainActivity.java。
public class MainActivity extends AppCompatActivity { private SeekBar seekBar; private Button button1; private SlideImageView slideImageView; private TextView resultText; private View flashView; private static final int flashTime = 800; private long timeStart = 0; private float timeUsed; @SuppressLint("ClickableViewAccessibility") @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); seekBar = findViewById(R.id.seekBar1); button1 = findViewById(R.id.button1); slideImageView = findViewById(R.id.slide_image_view); flashView = findViewById(R.id.flash_view); resultText = findViewById(R.id.show_result); slideImageView.setImageBitmap(BitmapFactory.decodeResource(getResources(), R.mipmap.slide_bg)); seekBar.setMax(10000); seekBar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener(){ @Override public void onProgressChanged(SeekBar seekBar, int progress, boolean fromUser) { slideImageView.setMove(progress*0.0001); } @Override public void onStartTrackingTouch(SeekBar seekBar) { timeStart = System.currentTimeMillis(); } @Override public void onStopTrackingTouch(SeekBar seekBar) { } }); seekBar.setOnTouchListener(new View.OnTouchListener(){ @Override public boolean onTouch(View v, MotionEvent event) { switch(event.getAction()){ case MotionEvent.ACTION_UP: timeUsed = (System.currentTimeMillis() - timeStart) / 1000.0f; boolean isTrue = slideImageView.isTrue(0.1);//允许有10%误差 if(isTrue) { flashShowAnime(); updateText("验证成功,耗时:" + timeUsed + "秒"); } else { updateText("验证失败"); } break; } return false; } }); button1.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { reInit(); } }); } private void updateText(final String s) { runOnUiThread(new Runnable() { @Override public void run() { resultText.setText(s); } }); } private void reInit() { slideImageView.setReDraw(); seekBar.setProgress(0); resultText.setText(""); flashView.setVisibility(View.INVISIBLE); } // 成功高亮动画 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()); flashView.setVisibility(View.VISIBLE); flashView.setAnimation(translateAnimation); translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { } @Override public void onAnimationEnd(Animation animation) { flashView.setVisibility(View.INVISIBLE); } @Override public void onAnimationRepeat(Animation animation) { } }); } }
上一篇:Android自定义收音机搜台控件RadioRulerView
栏 目:Android代码
下一篇:Flutter自定义搜索框效果
本文地址:http://www.codeinn.net/misctech/190372.html