最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Android手勢密碼view學習筆記(一)

 更新時間:2017年03月01日 09:06:53   作者:vv_小蟲  
這篇文章主要為大家詳細介紹了Android手勢密碼view的學習筆記,具有一定的參考價值,感興趣的小伙伴們可以參考一下

剛接觸Android的時候看到別人寫的手勢密碼view,然后當時就在想,我什么時候才能寫出如此高端的東西?? 沒關系,不要怕哈,說出這樣話的人不是你技術不咋地而是你不愿意花時間去研究它,其實也沒有那么難哦(世上無難事,只怕有心人?。?,下面我們就一步一步實現一個手勢密碼view。

想必都看過手勢密碼view,但我們還是看看我們今天要實現的效果吧:

上面是一個手勢view的提示view,下面是一個手勢view。

用法:

 <com.leo.library.view.GestureContentView
   android:id="@+id/id_gesture_pwd"
   android:layout_gravity="center_horizontal"
   android:layout_marginTop="10dp"
   android:layout_width="match_parent"
   android:layout_height="match_parent"
   app:column="3"
   app:row="3"
   app:padding="50dp"
   app:normalDrawable="@drawable/gesture_node_normal"
   app:selectedDrawable="@drawable/gesture_node_pressed"
   app:erroDrawable="@drawable/gesture_node_wrong"
   app:normalStrokeColor="#000"
   app:erroStrokeColor="#ff0000"
   app:strokeWidth="4dp"
   />

app打頭的是自定義的一些屬性,

attrs.xml:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="IndicatorView">
  <!--默認狀態(tài)的drawable-->
  <attr name="normalDrawable" format="reference" />
  <!--被選中狀態(tài)的drawable-->
  <attr name="selectedDrawable" format="reference" />
  <!--錯誤狀態(tài)的drawabe-->
  <attr name="erroDrawable" format="reference" />
  <!--列數-->
  <attr name="column" format="integer" />
  <!--行數-->
  <attr name="row" format="integer" />
  <!--padding值,padding值越大點越小-->
  <attr name="padding" format="dimension" />
  <!--默認連接線顏色-->
  <attr name="normalStrokeColor" format="color" />
  <!--錯誤連接線顏色-->
  <attr name="erroStrokeColor" format="color" />
  <!--連接線size-->
  <attr name="strokeWidth" format="dimension" />
 </declare-styleable>
</resources>

MainActivity.java:

public class MainActivity extends AppCompatActivity implements IGesturePwdCallBack {
 private GestureContentView mGestureView;
 private IndicatorView indicatorView;
 private TextView tvIndicator;

 private int count=0;
 private String pwd;
 @Override
 protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  setContentView(R.layout.activity_main);
  mGestureView= (GestureContentView) findViewById(R.id.id_gesture_pwd);
  indicatorView= (IndicatorView) findViewById(R.id.id_indicator_view);
  tvIndicator= (TextView) findViewById(R.id.id_indicator);
  mGestureView.setGesturePwdCallBack(this);
 }

 @Override
 public void callBack(List<Integer> pwds) {
  StringBuffer sbPwd=new StringBuffer();
  for (Integer pwd:pwds) {
   sbPwd.append(pwd);
  }
  tvIndicator.setText(sbPwd.toString());
  if(pwds!=null&&pwds.size()>0){
   indicatorView.setPwds(pwds);
  }
  if(count++==0){
   pwd=sbPwd.toString();
   Toast.makeText(this,"請再次繪制手勢密碼",Toast.LENGTH_SHORT).show();
   mGestureView.changePwdState(PointState.POINT_STATE_NORMAL,0);
  } else{
   count=0;
   if(pwd.equals(sbPwd.toString())){
    Toast.makeText(this,"密碼設置成功",Toast.LENGTH_SHORT).show();
   }else{
    Toast.makeText(this,"兩次密碼不一致,請重新繪制",Toast.LENGTH_SHORT).show();
    indicatorView.startAnimation(AnimationUtils.loadAnimation(this,R.anim.anim_shake));
    count=0;
    mGestureView.changePwdState(PointState.POINT_STATE_ERRO,0);
    new Handler().postDelayed(new Runnable() {
     @Override
     public void run() {
      mGestureView.changePwdState(PointState.POINT_STATE_NORMAL,0);
     }
    },1000);
   }
  }
 }
}

看不懂也沒關系啊,我們先明確下我們要完成的目標,然后一步一步實現:

先實現下我們的指示器view,因為實現了指示器view也就相當于實現了一半的手勢密碼view了:

實現思路:

1、我們需要知道指示器有多少行、多少列、默認顯示什么、選中后顯示什么?
2、然后根據傳入的密碼把對應的點顯示成選中狀態(tài),沒有選中的點為默認狀態(tài)。

好了,知道我們的思路,首先自定義一個view叫IndicatorView繼承view,然后重寫三個構造方法:

public class IndicatorView extends View {
 public IndicatorView(Context context) {
  this(context, null);
 }

 public IndicatorView(Context context, AttributeSet attrs) {
  this(context, attrs, 0);
 }

 public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  }
}

定義自定義屬性(在res/values下創(chuàng)建attrs.xml文件):

1、我們需要傳入的默認顯示圖片:

 <!--默認狀態(tài)的drawable-->
  <attr name="normalDrawable" format="reference" />

2、我們需要拿到傳入的選中時圖片:

<!--被選中狀態(tài)的drawable-->
  <attr name="selectedDrawable" format="reference" />

其它的一些屬性:

<?xml version="1.0" encoding="utf-8"?>
<resources>
 <declare-styleable name="IndicatorView">
  <!--默認狀態(tài)的drawable-->
  <attr name="normalDrawable" format="reference" />
  <!--被選中狀態(tài)的drawable-->
  <attr name="selectedDrawable" format="reference" />
  <!--列數-->
  <attr name="column" format="integer" />
  <!--行數-->
  <attr name="row" format="integer" />
   </declare-styleable>
</resources>

定義完屬性后,此時我們xml中就可以引用自定義view了:

<com.leo.library.view.IndicatorView
  android:id="@+id/id_indicator_view"
  android:layout_marginTop="20dp"
  android:layout_width="85dp"
  android:layout_height="85dp"
  android:layout_alignParentTop="true"
  android:layout_centerHorizontal="true"
  app:column="3"
  app:normalDrawable="@drawable/shape_white_indicator"
  app:padding="8dp"
  app:row="3"
  app:selectedDrawable="@drawable/shape_orange_indicator" />

注意:

中間的drawable文件可以在github項目中找到,鏈接我會在文章最后給出。

有了自定義屬性,然后我們在帶三個參數的構造方法中獲取我們在布局文件傳入的自定義屬性:

private static final int NUMBER_ROW = 3;
 private static final int NUMBER_COLUMN = 3;
 private int DEFAULT_PADDING = dp2px(10);
 private final int DEFAULT_SIZE = dp2px(40);

 private Bitmap mNormalBitmap;
 private Bitmap mSelectedBitmap;
 private int mRow = NUMBER_ROW;
 private int mColumn = NUMBER_COLUMN;

 public IndicatorView(Context context, AttributeSet attrs, int defStyleAttr) {
  super(context, attrs, defStyleAttr);
  final TypedArray a = context.obtainStyledAttributes(
    attrs, R.styleable.IndicatorView, defStyleAttr, 0);
  mNormalBitmap = drawableToBitmap(a.getDrawable(R.styleable.IndicatorView_normalDrawable));
  mSelectedBitmap = drawableToBitmap(a.getDrawable(R.styleable.IndicatorView_selectedDrawable));
  if (a.hasValue(R.styleable.IndicatorView_row)) {
   mRow = a.getInt(R.styleable.IndicatorView_row, NUMBER_ROW);
  }
  if (a.hasValue(R.styleable.IndicatorView_column)) {
   mColumn = a.getInt(R.styleable.IndicatorView_row, NUMBER_COLUMN);
  }
  if (a.hasValue(R.styleable.IndicatorView_padding)) {
   DEFAULT_PADDING = a.getDimensionPixelSize(R.styleable.IndicatorView_padding, DEFAULT_PADDING);
  }
 }

好了,現在我們已經拿到了我們想要的東西了,接下來我們需要知道我的view要多大,相比小伙伴都知道接下來要干什么了吧?對~! 我們需要重寫下onMeasure方法,然后指定我們view的大?。?/p>

 @Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
 }

那么我們該以一個什么樣的規(guī)則指定我們的view的大小呢?

1、當用戶自己指定了view的大小的話,我們就用用戶傳入的size,然后根據傳入的寬、高計算出我們的點的大小。

<com.leo.library.view.IndicatorView
  android:id="@+id/id_indicator_view"
  android:layout_marginTop="20dp"
  android:layout_width="85dp"
  android:layout_height="85dp"

2、如果用戶沒有指定view的大小,寬高都設置為wrap_content的話,我們需要根據用戶傳入的選中圖片跟沒選中圖片的大小計算view的大?。?/p>

android:layout_width="wrap_content"
android:layout_height="wrap_content"

好了,既然知道咋測量我們的view后,我們接下來就實現出來:

@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  int widthMode = MeasureSpec.getMode(widthMeasureSpec);
  int heightMode = MeasureSpec.getMode(heightMeasureSpec);
  float width = MeasureSpec.getSize(widthMeasureSpec);
  float height = MeasureSpec.getSize(heightMeasureSpec);
  float result=Math.min(width,height);
  height = getHeightValue(result, heightMode);
  width = getWidthValue(result, widthMode);
  }
 private float getHeightValue(float height, int heightMode) {
  //當size為確定的大小的話
  //每個點的高度等于(控件的高度-(行數+1)*padding值)/行數
  if (heightMode == MeasureSpec.EXACTLY) {
   mCellHeight = (height - (mRow + 1) * DEFAULT_PADDING) / mRow;
  } else {
   //高度不確定的話,我們就取選中的圖片跟未選中圖片中的高度的最小值
   mCellHeight = Math.min(mNormalBitmap.getHeight(), mSelectedBitmap.getHeight());
   //此時控件的高度=點的高度*行數+(行數+1)*默認padding值
   height = mCellHeight * mRow + (mRow + 1) * DEFAULT_PADDING;
  }
  return height;
 }

寬度計算方式也是一樣的話,只是行數換成了列數:

 private float getWidthValue(float width, int widthMode) {
  if (widthMode == MeasureSpec.EXACTLY) {
   mCellWidth = (width - (mColumn + 1) * DEFAULT_PADDING) / mColumn;
  } else {
   mCellWidth = Math.min(mNormalBitmap.getWidth(), mSelectedBitmap.getWidth());
   width = mCellWidth * mColumn + (mColumn + 1) * DEFAULT_PADDING;
  }
  return width;
 }

好了,現在是知道了點的高度跟寬度,然后控件的寬高自然也就知道了,但是如果我們傳入的選中的圖片跟未選擇的圖片大小不一樣咋辦呢?沒關系,接下來我們重新修改下圖片的size:

@Override
 protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
  .....
  height = getHeightValue(result, heightMode);
  width = getWidthValue(result, widthMode);
  setMeasuredDimension((int) width, (int) height);
  //重新修改圖片的size
  resizeBitmap(mCellWidth, mCellHeight);
 }
 private void resizeBitmap(float width, float height) {
  if (width > 0 && height > 0) {
   if (mNormalBitmap.getWidth() != width || mNormalBitmap.getHeight() !=height) {
    if (mNormalBitmap.getWidth() > 0 && mNormalBitmap.getHeight() > 0) {
     mNormalBitmap = Bitmap.createScaledBitmap(mNormalBitmap, (int) width, (int) height, false);
    }
   }
   if (mSelectedBitmap.getWidth()!=width || mSelectedBitmap.getHeight() !=height) {
    if (mSelectedBitmap.getWidth() > 0 && mSelectedBitmap.getHeight() > 0) {
     mSelectedBitmap = Bitmap.createScaledBitmap(mSelectedBitmap, (int) width, (int) height, false);
    }
   }
  }
 }

好了,圖片也拿到了,控件的寬高跟點的寬高都知道,所以接下來我們該進入我們的核心代碼了(重寫onDraw方法,畫出我們的點):

 @Override
 protected void onDraw(Canvas canvas) {
  super.onDraw(canvas);
  //遍歷行數
  for (int i = 0; i < mRow; i++) {
   //遍歷列數
   for (int j = 0; j < mColumn; j++) {
    float left = (j + 1) * DEFAULT_PADDING + j * mCellWidth;
    float top = (i + 1) * DEFAULT_PADDING + i * mCellHeight;
    //每個點代表的密碼值=點對應的行數值*列數+對應的列數
    //比如3*3的表格,然后第二排的第一個=1*3+0=3
    int num=i * mColumn + j;
    //此點是不是在傳入的密碼集合中?
    if (pwds!=null&&pwds.contains(num)) {
     //這個點在傳入的密碼集合中的話就畫一個選中的bitmap
     canvas.drawBitmap(mSelectedBitmap, left, top, null);
    } else {
     canvas.drawBitmap(mNormalBitmap, left, top, null);
    }
   }
  }
 }

嗯嗯??!然后我們暴露一個方法,讓外界傳入需要現實的密碼集合:

 public void setPwds(List<Integer> pwds) {
  if(pwds!=null)this.pwds=pwds;
  if (Looper.myLooper() == Looper.getMainLooper()) {
   invalidate();
  } else {
   postInvalidate();
  }
 }

好啦~~ 我們的指示器view就做完啦~~~ 是不是很簡單呢? 指示器view做完后,再想想手勢密碼view,是不是就只是差根據手勢改變,然后畫出我們的line呢?

現附上項目的github鏈接:
https://github.com/913453448/GestureContentView/

下一節(jié)我們將一起實現一下手勢密碼view。

Android手勢密碼view筆記(二)

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 淺析Android 模擬鍵盤鼠標事件

    淺析Android 模擬鍵盤鼠標事件

    本篇文章是對Android模擬鍵盤鼠標事件進行了詳細的分析介紹,需要的朋友參考下
    2013-06-06
  • Android Crash與ANR詳細介紹

    Android Crash與ANR詳細介紹

    對于Android開發(fā)的人來說,想必對Crash和ANR這倆都不陌生,并且都對其恨之入骨,因為它倆的產生會大大影響用戶體驗。所以,在此,結合本人的開發(fā)經驗,對其做個總結
    2022-11-11
  • Android中利用動態(tài)加載實現手機淘寶的節(jié)日特效

    Android中利用動態(tài)加載實現手機淘寶的節(jié)日特效

    這篇文章主要介紹了Android中利用動態(tài)加載實現手機淘寶的節(jié)日特效,非常不錯,具有參考借鑒價值,需要的朋友可以參考下
    2016-12-12
  • Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用詳解

    Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用詳解

    這篇文章主要給大家介紹了關于Android開發(fā)中l(wèi)ibs和jinLibs文件夾的作用的相關資料,文中通過圖文及示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面來一起看看吧。
    2017-09-09
  • 關于android studio升級4.1 某些插件使用不了的問題(Mac)

    關于android studio升級4.1 某些插件使用不了的問題(Mac)

    這篇文章主要介紹了關于android studio升級4.1 某些插件使用不了的問題(Mac),本文給大家分享解決方法供大家參考,感興趣的朋友跟隨小編一起看看吧
    2020-10-10
  • Android中使用TextView實現高仿京東淘寶各種倒計時效果

    Android中使用TextView實現高仿京東淘寶各種倒計時效果

    今天給大家?guī)淼氖莾H僅使用一個TextView實現一個高仿京東、淘寶、唯品會等各種電商APP的活動倒計時。今天小編把實現代碼分享到腳本之家平臺,對android textclock 倒計時效果感興趣的朋友參考下吧
    2016-10-10
  • Android ListView實現上拉加載下拉刷新和滑動刪除功能

    Android ListView實現上拉加載下拉刷新和滑動刪除功能

    這篇文章主要為大家詳細介紹了Android ListView實現上拉加載下拉刷新和滑動刪除功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2016-12-12
  • Android中Activity的生命周期探討

    Android中Activity的生命周期探討

    這篇文章主要介紹了Android中Activity的生命周期探討,本文同時講解了銷毀Activity、暫停與恢復、停止與重啟Activity等內容,需要的朋友可以參考下
    2014-10-10
  • Android 保存文件路徑方法

    Android 保存文件路徑方法

    今天小編就為大家分享一篇Android 保存文件路徑方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2018-08-08
  • Android實現滑動屏幕切換圖片

    Android實現滑動屏幕切換圖片

    這篇文章主要為大家詳細介紹了Android實現滑動屏幕切換圖片,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2018-08-08

最新評論

丰宁| 清新县| 蒙城县| 浪卡子县| 萍乡市| 民乐县| 鹤壁市| 仁寿县| 佛坪县| 平凉市| 盐津县| 屏东市| 和平区| 青龙| 马尔康县| 西林县| 儋州市| 兴文县| 宿松县| 武安市| 炉霍县| 通州市| 遂平县| 琼中| 怀柔区| 揭阳市| 巴彦淖尔市| 望奎县| 拉萨市| 睢宁县| 呼和浩特市| 重庆市| 连南| 临高县| 中西区| 德保县| 互助| 榕江县| 额济纳旗| 衡阳县| 泽库县|