国产探花免费观看_亚洲丰满少妇自慰呻吟_97日韩有码在线_资源在线日韩欧美_一区二区精品毛片,辰东完美世界有声小说,欢乐颂第一季,yy玄幻小说排行榜完本

首頁 > 系統(tǒng) > Android > 正文

Android手勢密碼view學(xué)習(xí)筆記(一)

2019-10-23 19:44:13
字體:
供稿:網(wǎng)友

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

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

Android,手勢密碼,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">  <!--默認(rèn)狀態(tài)的drawable-->  <attr name="normalDrawable" format="reference" />  <!--被選中狀態(tài)的drawable-->  <attr name="selectedDrawable" format="reference" />  <!--錯誤狀態(tài)的drawabe-->  <attr name="erroDrawable" format="reference" />  <!--列數(shù)-->  <attr name="column" format="integer" />  <!--行數(shù)-->  <attr name="row" format="integer" />  <!--padding值,padding值越大點越小-->  <attr name="padding" format="dimension" />  <!--默認(rèn)連接線顏色-->  <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,"密碼設(shè)置成功",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);   }  } }}

看不懂也沒關(guān)系啊,我們先明確下我們要完成的目標(biāo),然后一步一步實現(xiàn):

先實現(xiàn)下我們的指示器view,因為實現(xiàn)了指示器view也就相當(dāng)于實現(xiàn)了一半的手勢密碼view了:

Android,手勢密碼,view

實現(xiàn)思路:

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

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

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、我們需要傳入的默認(rèn)顯示圖片:

 <!--默認(rèn)狀態(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">  <!--默認(rèn)狀態(tài)的drawable-->  <attr name="normalDrawable" format="reference" />  <!--被選中狀態(tài)的drawable-->  <attr name="selectedDrawable" format="reference" />  <!--列數(shù)-->  <attr name="column" format="integer" />  <!--行數(shù)-->  <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項目中找到,鏈接我會在文章最后給出。

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

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);  } }

好了,現(xiàn)在我們已經(jīng)拿到了我們想要的東西了,接下來我們需要知道我的view要多大,相比小伙伴都知道接下來要干什么了吧?對~! 我們需要重寫下onMeasure方法,然后指定我們view的大小:

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

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

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

<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的大小,寬高都設(shè)置為wrap_content的話,我們需要根據(jù)用戶傳入的選中圖片跟沒選中圖片的大小計算view的大小:

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

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

@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) {  //當(dāng)size為確定的大小的話  //每個點的高度等于(控件的高度-(行數(shù)+1)*padding值)/行數(shù)  if (heightMode == MeasureSpec.EXACTLY) {   mCellHeight = (height - (mRow + 1) * DEFAULT_PADDING) / mRow;  } else {   //高度不確定的話,我們就取選中的圖片跟未選中圖片中的高度的最小值   mCellHeight = Math.min(mNormalBitmap.getHeight(), mSelectedBitmap.getHeight());   //此時控件的高度=點的高度*行數(shù)+(行數(shù)+1)*默認(rèn)padding值   height = mCellHeight * mRow + (mRow + 1) * DEFAULT_PADDING;  }  return height; }

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

 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; }

好了,現(xiàn)在是知道了點的高度跟寬度,然后控件的寬高自然也就知道了,但是如果我們傳入的選中的圖片跟未選擇的圖片大小不一樣咋辦呢?沒關(guān)系,接下來我們重新修改下圖片的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);    }   }  } }

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

 @Override protected void onDraw(Canvas canvas) {  super.onDraw(canvas);  //遍歷行數(shù)  for (int i = 0; i < mRow; i++) {   //遍歷列數(shù)   for (int j = 0; j < mColumn; j++) {    float left = (j + 1) * DEFAULT_PADDING + j * mCellWidth;    float top = (i + 1) * DEFAULT_PADDING + i * mCellHeight;    //每個點代表的密碼值=點對應(yīng)的行數(shù)值*列數(shù)+對應(yīng)的列數(shù)    //比如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);    }   }  } }

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

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

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

現(xiàn)附上項目的github鏈接:
https://github.com/913453448/GestureContentView/

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

Android手勢密碼view筆記(二)

以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持VEVB武林網(wǎng)。


注:相關(guān)教程知識閱讀請移步到Android開發(fā)頻道。
發(fā)表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發(fā)表
主站蜘蛛池模板: 三台县| 镇平县| 逊克县| 衡阳县| 新余市| 上犹县| 凤城市| 高唐县| 册亨县| 武川县| 竹溪县| 蓬溪县| 利辛县| 鄱阳县| 通许县| 镇巴县| 广元市| 社会| 崇州市| 吉安市| 平舆县| 城固县| 黄浦区| 淳化县| 集安市| 崇仁县| 德庆县| 腾冲县| 海盐县| 烟台市| 金山区| 临泽县| 奉节县| 新田县| 蒲城县| 四平市| 新沂市| 巫山县| 淮滨县| 苍山县| 广灵县|