The declare-styleable is used to set attributes to components. We have declared style attributes for Lock9View in attrs_lock_9_view.xml as shown above. These style attributes can be set in xml where the Lock9View is placed.
                                           Lock9View.java
| 
 
packagecom.android.androiddelight.lock9view.utils; import java.util.ArrayList; 
import java.util.List; 
import com.android.androiddelight.lock9view.R; 
import android.content.Context; 
import android.content.res.TypedArray; 
import android.graphics.Bitmap; 
import android.graphics.Canvas; 
import android.graphics.Color; 
import android.graphics.Paint; 
import android.graphics.Paint.Style; 
import android.graphics.PorterDuff; 
import android.graphics.drawable.Drawable; 
import android.util.AttributeSet; 
import android.util.DisplayMetrics; 
import android.util.Pair; 
import android.view.MotionEvent; 
import android.view.View; 
import android.view.ViewGroup; 
 
 publicclassLock9View extendsViewGroup { 
 
  privatePaint paint; 
  privateBitmap bitmap; 
  privateCanvas canvas; 
  privateList<Pair<NodeView, NodeView>> lineList;   privateNodeView currentNode; 
   | 
  privateStringBuilder pwdSb;
  privateCallBack callBack;
  
  privateDrawable nodeSrc;
  privateDrawable nodeOnSrc;
public 
        this(context, null);
    }
public 
        this(context, attrs, 0
    } 
public 
        this(context, attrs, defStyleAttr, 0
    } 
public int int 
        super(context, attrs, defStyleAttr); 
        initFromAttributes(attrs, defStyleAttr);
    }
private int 
        final TypedArray a = getContext().obtainStyledAttributes(attrs,    R.styleable.Lock9View, defStyleAttr, 0
        nodeSrc = a.getDrawable(R.styleable.Lock9View_nodeSrc);
        nodeOnSrc = a.getDrawable(R.styleable.Lock9View_nodeOnSrc);
        int lineColor = Color.argb(0000
        lineColor = a.getColor(R.styleable.Lock9View_lineColor, lineColor);
        float lineWidth = 20.0f;
        lineWidth = a.getDimension(R.styleable.Lock9View_lineWidth, lineWidth);
        a.recycle();
        paint = new Paint(Paint.DITHER_FLAG);
        paint.setStyle(Style.STROKE);
        paint.setStrokeWidth(lineWidth);
        paint.setColor(lineColor);
        paint.setAntiAlias(true);
        DisplayMetrics dm = getResources().getDisplayMetrics();
        bitmap = Bitmap.createBitmap(dm.widthPixels, dm.widthPixels,   Bitmap.Config.ARGB_8888);
        canvas = new Canvas();
        canvas.setBitmap(bitmap);
        for (int n = 0; n < 9; n++) {
            NodeView node = new NodeView(getContext(), n + 1);
            addView(node);
        }
        lineList = new ArrayList<Pair<NodeView,NodeView>>();
        pwdSb = new StringBuilder();
        setWillNotDraw(false);
    } 
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        setMeasuredDimension(widthMeasureSpec, widthMeasureSpec); 
    }
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
        if (!changed) {
            return;
        }
        int width = right - left;
        int nodeWidth = width / 3;
        int nodePadding = nodeWidth / 6;
        for (int n = 0; n < 9; n++) {
            NodeView node = (NodeView) getChildAt(n);
            int row = n / 3;
            int col = n % 3;
            int l = col * nodeWidth + nodePadding;
            int t = row * nodeWidth + nodePadding;
            int r = col * nodeWidth + nodeWidth - nodePadding;
            int b = row * nodeWidth + nodeWidth - nodePadding;
            node.layout(l, t, r, b);
        }
    }
@Override 
protected
        canvas.drawBitmap(bitmap, 0, 0, null);
    }
@Override 
protected boolean onTouchEvent(MotionEvent event) {
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN:
            case MotionEvent.ACTION_MOVE:
                NodeView nodeAt = getNodeAt(event.getX(), event.getY());
                if (nodeAt == null && currentNode == null) { 
                    return true;
                } else { 
                    clearScreenAndDrawList(); 
                    if (currentNode == null) {
                        currentNode = nodeAt;
                        currentNode.setHighLighted(true);
                        pwdSb.append(currentNode.getNum());
                    }
                    else if (nodeAt == null || nodeAt.isHighLighted()) {
                         
                        canvas.drawLine(currentNode.getCenterX(), currentNode.getCenterY(), event.getX(), event.getY(), paint);
                    } else { 
                        canvas.drawLine(currentNode.getCenterX(), currentNode.getCenterY(), nodeAt.getCenterX(), nodeAt.getCenterY(), paint);                         
            nodeAt.setHighLighted(true);
            Pair<NodeView, NodeView> pair = new Pair<NodeView, NodeView>(currentNode, nodeAt);
            lineList.add(pair);
                        
             currentNode = nodeAt;
             pwdSb.append(currentNode.getNum());
         }
             invalidate();
         }
         return true;
         
         case MotionEvent.ACTION_UP:
               
                if (pwdSb.length() <= 0) {
                    return super.onTouchEvent(event);
                }
              
                if (callBack != null) {
                    callBack.onFinish(pwdSb.toString());
                    pwdSb.setLength(0); 
                }
               
                currentNode = null;
                lineList.clear();
                clearScreenAndDrawList();
                
                for (int n = 0; n < getChildCount(); n++) {
                    NodeView node = (NodeView) getChildAt(n);
                    node.setHighLighted(false);
                }
                
                invalidate();
                return true;
        }
        return super.onTouchEvent(event);
    }
private void clearScreenAndDrawList() {
     canvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);
     for (Pair<NodeView, NodeView> pair : lineList) {
          canvas.drawLine(pair.first.getCenterX(), pair.first.getCenterY(),  pair.second.getCenterX(), pair.second.getCenterY(), paint);
        }
    }
private NodeView getNodeAt(float x, float y) {
        
          for (int n = 0; n < getChildCount(); n++) {
            NodeView node = (NodeView) getChildAt(n);
            if (!(x >= node.getLeft() && x < node.getRight())) {
                continue;
            }
            if (!(y >= node.getTop() && y < node.getBottom())) {
                continue;
            }
            return node;
        }
        return null;
    }
public void setCallBack(CallBack callBack) {
        this.callBack = callBack;
    }
public class NodeView extends View {
        private int num;
        private  boolean highLighted;
        private  NodeView(Context context) {
            super(context);
        }
        public 
            this(context);
            this.num = num;
            highLighted = false;
            if (nodeSrc == null) {
                setBackgroundResource(0);
            } else {
                setBackgroundDrawable(nodeSrc);
            }
        }
        public boolean isHighLighted() {
            return highLighted;
        }
        public 
            this.highLighted = highLighted;
            if (highLighted) {
                if (nodeOnSrc == null) {
                    setBackgroundResource(0);
                } else {
                    setBackgroundDrawable(nodeOnSrc);
                }
            } else {
                if (nodeSrc == null) {
                    setBackgroundResource(0);
                } else {
                    setBackgroundDrawable(nodeSrc);
                }
            }
        }
        public int getCenterX() {
            return (getLeft() + getRight()) / 2;
        }
        public int getCenterY() {
            return (getTop() + getBottom()) / 2;
        }
        public int getNum() {
            return num;
        }
        public void setNum(int num) {
            this.num = num;
        }
    }
public interface CallBack {
        public void onFinish(String password);
    }
}
Now we are ready with the 9 Pattern View. Next i am going to declare this view inside my main layout that is activity_main.xml.
Step 5 : Open the activity_main.xml under res/layout and fill it with following code.
activity_main.xml
| 
<?xml version = "1.0" encoding = "utf-8"?> 
<FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android"xmlns:app = "http://schemas.android.com/apk/res-auto"
 android:layout_width = "match_parent"
 android:layout_height = "match_parent"
 android:background = "#ff222233">
 
      <!--Include the Lock9View along with the package where it is located --> 
      <com.android.androiddelight.lock9view.utils.Lock9View android:id = "@+id/lock_9_view"
 android:layout_width = "match_parent"
 android:layout_height = "wrap_content"
 android:layout_gravity = "center"
 
        <!--Note : These  attributes are from declare-styleable  -->app:nodeSrc = "@drawable/lock_9_view_node_normal"
 app:nodeOnSrc = "@drawable/lock_9_view_node_highlighted"
 app:lineColor = "#ff006699"
 app:lineWidth = "8dp" />
 
 </FrameLayout>
 
 
Step 6 : Open the MainActivity.java under src/package we need to declare the Lock9View and reference it in MainActivity. Write the code as follows in MainActivity. 
 
 
MainActivity.java
| 
 
packagecom.android.androiddelight.lock9view; 
import com.android.androiddelight.lock9view.utils.Lock9View; 
 
 
 
 
 
 |  
 
 
 
 
 
 publicclassMainActivity extendsActionBarActivity { 
 
 privateLock9View lock9View; 
private static String MY_PREFS_NAME = "PatternLock";private static String PATTERN_KEY;
  
SharedPreferences prefs; 
 
 @Override 
public voidonCreate(Bundle savedInstanceState){ 
   super.onCreate(savedInstanceState);    setContentView(R.layout.activity_main); 
 
   prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);  
    
   lock9View = (Lock9View) findViewById(R.id.lock_9_view); 
 
   lock9View.setCallBack(new Lock9View.CallBack() {
 @Override
 
public void onFinish(String password) {PATTERN_KEY = prefs.getString("Pattern", "invalid");
 
 if(PATTERN_KEY.equals("invalid")){
 Toast.makeText(MainActivity.this, "Options --> Create new Pattern", Toast.LENGTH_LONG).show();
 }else{
 if(password.equals(PATTERN_KEY)){
 Intent intent = new Intent(MainActivity.this, WelcomeActivity.class);
 startActivity(intent);
 finish();
 Toast.makeText(MainActivity.this, "Login success!",   Toast.LENGTH_SHORT).show();
 }else{
 Toast.makeText(MainActivity.this, "Pattern incorrect!", Toast.LENGTH_SHORT).show();
 }
 }
 }
 });
  
 
 
 
 
 
 
Step 7 : We have to create one more activity to change the pattern. So Create a new Activity by going to File ⇒ New ⇒ Other ⇒ Android Activity. Fill all the details and name your activity as ChangeActivity.
 
 
In ChangeActivity we need 2 Lock9View 1- for drawing new pattern 2 - for confirm drawing pattern 
   
Step 8 : Open the activity_change.xml under res/layout and fill it with following code. 
 
activity_change.xml
| 
 
<?xml version = "1.0" encoding = "utf-8"?>
<FrameLayout xmlns:android = "http://schemas.android.com/apk/res/android"xmlns:app = "http://schemas.android.com/apk/res-auto"
 android:layout_width = "match_parent"
 android:layout_height = "match_parent"
 android:background = "#ff222233">
 
    <!--TextView for prompting the users  --> 
      <TextViewandroid:id = "@+id/tvMsg"
 android:layout_width = "wrap_content"
 android:layout_height = "wrap_content"
 android:layout_marginLeft = "5dp"
 android:layout_marginTop = "20dp"
 android:textAppearance = "?android:attr/textAppearanceSmall"
 android:textColor = "#ff006699" />
 
 
      <!-- FrameLayout to hold the 1st Lock9View --> 
      <FrameLayoutandroid:id = "@+id/enterPattern"
 android:layout_width = "wrap_content"
 android:layout_height = "wrap_content"
 android:layout_gravity = "center" >
 
  
      <com.android.androiddelight.lock9view.utils.Lock9View android:id = "@+id/lock_9_view"
 android:layout_width = "match_parent"
 android:layout_height = "wrap_content"
 android:layout_gravity = "center"
 app:nodeSrc = "@drawable/lock_9_view_node_normal"
 app:nodeOnSrc = "@drawable/lock_9_view_node_highlighted"
 app:lineColor = "#ff006699"
 app:lineWidth = "8dp" />
     
       </FrameLayout> 
 
      <!-- FrameLayout to hold the 2nd Lock9View -->
      <FrameLayoutandroid:id = "@+id/confirmPattern"
 android:layout_width = "wrap_content"
 android:layout_height = "wrap_content"
 android:layout_gravity = "center"
 
        android:visibility = "gone" >  
  
      <com.android.androiddelight.lock9view.utils.Lock9View android:id = "@+id/lock_viewConfirm"
 android:layout_width = "match_parent"
 android:layout_height = "wrap_content"
 android:layout_gravity = "center"
app:nodeSrc = "@drawable/lock_9_view_node_normal"
 app:nodeOnSrc = "@drawable/lock_9_view_node_highlighted"
 app:lineColor = "#ff006699"
 app:lineWidth = "8dp" />
 
      </FrameLayout>  
</FrameLayout>  
 
The layout is build. Now getting to java code to write business logic. 
Step 9 : Open the ChangeActivity.java  under src/package and write down the code as follows.
                                                            ChangeActivity.java
| 
 
 packagecom.android.androiddelight.lock9view; |  
 
 
 
 
 
 
 
publicclassChangeActivity extendsActionBarActivity {
privateFrameLayout enterPatternContainer, confirmPatternContainer; 
 
private Lock9View lockViewFirstTry, lockViewConfirm; private static String MY_PREFS_NAME = "PatternLock"; 
private static String PATTERN_KEY; 
 
 
 
 
SharedPreferences prefs;private Editor editor;private 
TextView tvMsg;private  
 
 
 
 
 
 
@Override 
protected voidonCreate(Bundle savedInstanceState){ 
  super.onCreate(savedInstanceState); 
  setContentView(R.layout.activity_change); 
  prefs = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE);editor = getSharedPreferences(MY_PREFS_NAME, MODE_PRIVATE).edit();
 
   
  tvMsg = (TextView)findViewById(R.id.tvMsg); 
  tvMsg.setText(getResources().getString(R.string.draw_pattern_msg));  
     
  enterPatternContainer = (FrameLayout) findViewById(R.id.enterPattern);confirmPatternContainer = (FrameLayout) findViewById(R.id.confirmPattern);
 
 
lockViewFirstTry = (Lock9View) findViewById(R.id.lock_viewFirstTry);
 lockViewConfirm =  (Lock9View) findViewById(R.id.lock_viewConfirm);
 
 
//we can get a call back string when ever user interacts  
//with the pattern lock view  
 
lockViewFirstTry.setCallBack(new Lock9View.CallBack() {
 
@Override 
  public void onFinish(String password) {PATTERN_KEY = password;
 enterPatternContainer.setVisibility(View.GONE);
 tvMsg.setText(getResources().getString
 
     (R.string.redraw_confirm_pattern_msg));confirmPatternContainer.setVisibility(View.VISIBLE);
 }
 });
 
 
lockViewConfirm.setCallBack(new Lock9View.CallBack() {
 
 @Override
  public void onFinish(String password) { if(password.equals(PATTERN_KEY)){
 Toast.makeText(getApplicationContext(),
 
    "Pattern created successfully!",  
    Toast.LENGTH_SHORT).show();editor.putString("Pattern", password);
 editor.commit();
 Intent intent = new Intent(ChangeActivity.this, MainActivity.class);
 startActivity(intent);
 finish();
 }else{
 Toast.makeText(getApplicationContext(),
 
    "You have drawn the wrong Pattern", Toast.LENGTH_SHORT).show();}
 }
 });
 
 @Override 
public boolean onCreateOptionsMenu(Menu menu) {getMenuInflater().inflate(R.menu.menu_change, menu);
 return true;
 }
 
 @Override 
public boolean onOptionsItemSelected(MenuItem item) { 
switch (item.getItemId()) {
 
 case R.id.contact:
 new AlertDialog.Builder(this)
 .setTitle("Android-Lock9View")
 .setMessage(
 "Email : anfersyed@gmail.com"
 +"\nBlog  : http://android-delight.blogspot.in/")
 .setPositiveButton("OK", null).show();
 return true;
 default:
 return super.onOptionsItemSelected(item);
 }
 }
 
}  
 
Checkout the live demo : 
 
 
 
  |  
 | 
 
 
No comments:
Post a Comment