Se acerca el año nuevo y los sobres rojos son infinitos. Cuando estaba agarrando sobres rojos, accidentalmente descubrí que la interfaz de la bolsa de la suerte de Baidu es bastante buena, así que me tomé el tiempo de escribir un artículo para completar la interfaz de Baidu Red Envelope.
Por supuesto, esta es en realidad una versión evolutiva de la interfaz de desbloqueo. Sin embargo, contiene muchos puntos de conocimiento. Escriba una publicación de blog para grabarlo y ver qué puntos técnicos específicos hay. Echa un vistazo a las representaciones de Baidu:
1. Ideas de programación
Mirando la interfaz, no es difícil descubrir que es un contenedor que pone nueve imágenes. El dibujo en realidad puede crear otra vista transparente y es responsable de dibujar líneas y círculos. A continuación, presentaremos el proceso de implementación.
1. ViewGroup personalizado
Sabemos que ViewGroup personalizado debe implementar su método OnLayout (). Este método se llama al establecer la posición y el tamaño de la subvisión. También hay un método OnMeash (), que mide la vista y su contenido para determinar el ancho y la altura de la vista.
㈡ Almacen las posiciones de sus puntos y círculos y parámetros de dibujo
Al volver a la interfaz, no se guardará el contenido de la última interfaz de dibujo. Debe almacenarse en caso de volver a dibujar para atraer la interfaz
㈢ Animación de zoom simple
㈣ Interfaz de dibujo de implementación de vista de vista
㈤ Cuando se complete el dibujo, borre el contenido de dibujo de la interfaz y asegúrese de que las imágenes duplicadas no estén conectadas.
Completaremos estos pasos a continuación.
2. Personalizar ViewGroup
La tarea inicial es distribuir uniformemente las nueve imágenes a la ubicación de las imágenes y mostrarlas en la interfaz del teléfono móvil. El código es el siguiente:
clase pública lyjviewGroup extiende ViewGroup implementa lyjgestiedrawline.onanimationCallback {/*** Ancho de cada área de punto*/private int ChildWidth;/**** Context*/context con contexto privado;/**** Ubicación del punto de imagen*/Lista privada <lyjgesturePoint> Lista;/**** Cree una vista por encima de la vista de la vista. */private lyjgestureView gearDrawline; private int basenum = 5; public lyjviewGroup (context con contexto) {super (context); this.context = context; this.list = new ArrayList <> (); DisplayMetrics Metric = New DisplayMetrics (); ((Actividad) contexto) .getwindowmanager (). getDefaultDisplay (). getMetrics (métrico); childwidth = métrico.widthpixels / 3; // Screen width (pixels) addChild();// Initialize a viewgestureDrawline that can draw lines = new LYJGestureView(context, list);gestureDrawline.setAnimationCallback(this);}public void setParentView(ViewGroup parent){// Get the width of the screen DisplayMetrics metric = new DisplayMetrics();((Activity) contexto) .getwindowmanager (). getDefaultDisplay (). getMetrics (métrico); int width = metric.widthpixels; LayoutParams LayoutParams = New LayoutParams (ancho,, width);this.setLayoutParams(layoutParams);gestureDrawline.setLayoutParams(layoutParams);parent.addView(this);parent.addView(gestureDrawline);}@Overrideprotected void onLayout(boolean changed, int l, int t, int r, int b) {for (int i = 0; i < getChildCount(); i ++) {// What Row int rowspan = i /3; // qué columna int columna = i % 3; android.view.view v = getChildat (i); V.Layout (columna * Childwidth + Childwidth /Basenum, Rowspan * Childwidth + Childwidth /Basenum, columna * Childwidth + Childwidth - Childwidth / / / / / / basenum);}}@overrideProtected nulo onMeASure (int widthMeasureSpec, int hightmeasureSpec) {super.onMeASure (widthMeasureSpec, HeightMeaseSpec); // Traversal establece el tamaño de cada vista infantil para (int i = 0; i <getChildCount (); i ++) {View v = = getChildAt(i);v.measure(widthMeasureSpec, heightMeasureSpec);}}private void addChild() {for (int i = 0; i < 9; i++) {ImageView image = new ImageView(context);image.setBackgroundResource(R.drawable.marker);this.addView(image);invalidate();// Which row int rowspan = i / 3; // ¿Qué columna int columna = i % 3; // Definir las coordenadas de las esquinas superior izquierda e inferior derecha del punto int leftx = column * Childwidth + Childwidth / Basenum; int topy = Rowspan * Childwidth + infancia de infancia / basenum; int derecha = column * columna * Childwidth + Childwidth - Childwidth / Basenum; intotth + ROWSPAN * ChildWidtpan * ChildwidTh + ROWSPAN * ChildWidTh + ROWSPAN * BOTHYPAN * ChildWidTh + ROWNTH + ROWSPAN * COMENTO * COMENTADO * Childwidth - Childwidth / Basenum; lyjgesturePoint p = new LyjgesturePoint (LeftX, Topy, Rightx, Bottomy, I); this.list.add (p);}}@overRidePublic Void startanimationImation (int i) {animación animación = animaciónUtils.loadAnimation (getContext (),,,,,,,,,,), R.anim.gridLayout_child_scale_anim); getChildat (i) .Startanimation (animación);}}3. Personalizar clases de puntos
Como su nombre indica, es obtener los atributos relevantes del punto, entre los cuales las coordenadas de la esquina superior izquierda de la imagen de atributo básico y las coordenadas de la esquina inferior derecha de la imagen, calculen la posición central de la imagen para obtener el punto central de la imagen. Marca de estado que indica si el punto se dibuja a la imagen. Aquí están las clases físicas:
clase pública lyjgesturePoint {private Point PointleftTop; // esquina superior de la esquina izquierda Coordinada Punto privado PoinTrightBottom; // La esquina inferior derecha coordenada privada int CenterX; // Image Center Point X Coordinate private int centery; // Image Center Point y coordenada int -int PointState; // si la imagen se hizo clic en private int puntos de puntos;} public void setPointState (int pointState) {this.PointState = PointState;} public Point getPointLeftToP () {return PointleftToP;} public Point getPoInTrightBottom () {return PoIntrightBottom;} public lyjgesturePoint (int INT, int top, int correcto, int i) {this este. Punto (izquierda, arriba); this.poinTrightBottom = New Point (Right, Bottom); this.num = i;} public int getCenterX () {this.centerx = (this.pointLeftTop.x+this.poinTrightBottom.x)/2; return CenterX;} public int getCentery () {this.centery = (this.pointlefttop.y+this.pointrightbottom.y)/2; return centery;}}4. Clase de círculo personalizado
Esta clase es más simple y tiene tres propiedades (coordenadas y radio del punto central del círculo). El código es el siguiente:
clase pública lyjcirclepoint {private int redondex; // Circle Center Point X Coordinate private int Roundy; // Circle Center Point Y Coordinate Private int Radio; // Circle Radius public int getRadiu () {return Radio;} public int getRoundx () {return Roundx;} public int radio) {this.roundx = Roundx; this.roundy = Roundy; this.radiu = radio;}}5. Implementar la vista de clase de dibujo personalizado
El código es el siguiente:
public class LYJGestureView extends android.view.View {/**** Declare straight line brush*/private Paint paint;/**** Declare circle brush*/private Paint circlePaint;/**** Canvas*/private Canvas canvas;/**** Bitmap*/private Bitmap bitmap;/**** A collection of each view coordinates is used to determine whether the points are in it*/private Lista <lyjgesturepoint> list;/**** registre las líneas dibujadas*/Lista privada <par <lyjgesturePoint, lyjgesturePoint >> lineList;/**** registrar el círculo dibujado*/private list <lyjcirclepoint> circlePoints;/*** ¿Qué punto es el dedo actualmente en*/lyjgesturePoint cotentPoint;/**** presione la animación*/privado privado? AnimationCallback; Interfaz pública OnanimationCallback {public void startanimationImage (int i);} public void setanimationCallback (onanimationCallback animationCallback) {this.animationCallback = AnimationCallback;} public lyjgestureView (contexto, contexto, list <lyjgesturepoin> list) {super (context); log.i (getClass (). getName (), "gestiedrawline"); pintar = new Paint (pintar.dal_flag); // Crear un círculo círculo circlePaint = new Paint (pintura DisplayMetrics (); ((Activity) Context) .GetWindowManager (). BitMap.CreateBitMap (Metric.WidthPixels, Metric.heightpixels, bitmap.config.argb_8888); // Establezca el ancho y la altura del lienzo de mapa de bits = new Canvas (); Canvas.SetBitMap (bitmap); pintar.setStyle (pintar.style.stroke); // establecer pintura sin relleno. pintar.setantialias (true); // no se muestra jagged circlePaint.setStyle (pintar.style.fill); circlePaint.setStrokeWidth (1); circlePaint.setantialias (true); circlePaint.setColor (color.rgb (245, 142, 33)); this.list = list; this.linelist ArrayList <> (); this.circlePoints = new ArrayList <> ();}@overRidePublic boolean onTouchEvent (MotionEvent Event) {switch (event.getAction ()) {case MotionEvent.Action_down: // Determina qué punto el clic actual está en CurrentPoint = GetPointat ((int) Event.getX (), (int) event.get.get ();); {CurrentPoint.SetPointState (constants.point_state_selected); this.AnimationCallback.StartanimationImage (currentPoint.getNum ()); Canvas.DrawCircle (CurrentPoint.getCenterX (), currentPoint.getCentery (), 20, circlePaint); circlePoints.add (new LyJCirclePoint (CurrentPoint.GetCenterX (), CurrentPoint.getCentery (), 20));} Invalideo ();) MotionEvent.Action_move: ClearScreenAndDrawlist (); // Obtenga el punto donde la posición móvil actual es lyjgesturePoint Pointat = getPointat ((int) event.getx (), (int) event.gety ()); if (currentPoint == null && pointat == null) {// presione su dedo en la pantalla para deslizarlo. Si el punto final y el punto de partida no son la imagen, return true;} else {// Significa que el dedo del usuario se mueve al punto if (currentPoint == null) {// primero determine si el punto de corriente es nulo // si está vacío, entonces asigne el punto que se movió a la punta de punto de corriente = punto; // establece el punto de punto de corriente para seleccionar el estado; currentPoint.setPointState (constants.point_state_selected);}} // Si el punto a la que se movió no es el área de la imagen o moverse a su propio lugar, o la imagen ya está seleccionada, simplemente dibuje una línea recta si (Pointat == NULL || CurrentPoint.equals (Pointat) || Constants.Point_State_Selected == Pointat.getPointState ()) {Canvas.DrawCircle (currentPoint.getCenterX (), currentPoint.getCentery (), 20, circlePaint); circlePoint.add (new LyJCirclePoint (currentPoint.getCenterX (), currentPoint.getCenteryery (), 20)); Canvas.drawline (currentPoint.GetCenterx (), CurrentPointery (), (), 20)); Event.getx (), event.gety (), pintar);} else {// dibuje dos líneas rectas en otras situaciones, guarde el círculo de dibujo y la línea recta, y llame a la animación de zoom de la imagen presionada Canvas.DrawCircle (Pointat.getCenterx (), Pointat.getCentery (), 20, CirclePaint); CirclePoints.add (new LyjCirclePoint (PointAt.., (), (), (), (), (); Pointat.getCentery (), 20)); this.AnimationCallback.StartanimationImage (Pointat.getNum ()); Pointat.SetPointState (constants.point_state_selected); Canvas.Drawline (currentPoint.getCenterX (), CurrentPoint.getCenteryery (), Pointat.getCenterX (), Pointat.getCentery (), Paint); LyjgesturePoint> par = new Par <> (CurrentPoint, Pointat); Linelist.Add (par); CurrentPoint = Pointat; // Establezca el punto seleccionado en el punto de corriente. } invalidate (); // repintear break; case MotionEvent.Action_Up: ClearScreenAndDrawlist (); // Prevenía una línea adicional con sin punto de finalización NUEVO Handler (). PostDelayed (NewLinerUnnable (), 1000); // Borrar la interfaz de dibujo después de 1 segundo Invalidato (); // Repainter void run () {// Borrar la colección de puntos de guardado y círculos Linelist.clear (); circlePoints.clear (); // Vuelva a dar para (lyjgesturePoint p: list) {// establecerlo para inicializar el estado no seleccionado p.setPointState (constants.point_state_normal);} Invalidate ();}}/*** A través de la posición de punto, vaya a la colección para encontrar qué punto se incluye en ** @param x* @param y* @return si no se encuentra, regresa null, que significa que el tiempo se mueve el tiempo que pertenece a la actualidad de la corriente de la corriente. Puntos*/private lyjgesturePoint getPointat (int x, int y) {for (lyJgesturePoint Point: list) {// Determinar primero si el punto está en la coordenada x de la imagen int tourtex = punto.getPointLeftToP (). x; int rectex = punto.getPoInTrightBottom la siguiente comparación continúa;} // en el juicio si el punto está en la coordenada y de la imagen int topy = Point.getPointLeftToP (). y; int Bottomy = Point.getPoInTrightBottom (). Y; if (! (Y> = Topy && Y <Bottomy) {// Si falsa, omita la siguiente comparación; atravesando hasta el punto. Punto de retorno;} return null;}/*** Borre todas las líneas en la pantalla, y luego dibuje las líneas en la colección*/private void clareScreenAndDrawlist () {Canvas.DrawColor (color.transparent, porterduff.mode.clear); para (par <lyjgesturePoint, lyjgesturePoint> par: linelist) {canvas.drawline (par.first.getCenterx (), par.first.getCentery (), par.second.getCenterX (), par.second.getCentery (), pintar); // line -line} para (lyjcirclepoint lyjcircircircircircircircircircircirccir CirclePoints) {Canvas.DrawCircle (lyjcirclepoint.getRoundx (), lyjcirclepoint.getRoundy (), lyjcirclepoint.getRadiu (), circlePaint);}} // Dibuje el lienzo creado con bitmap @overrideprotectect boid ondraw (canvas) {Canvas.DrawbitMap (Bitmap, 0, 0, Null);}}De esta manera, puede obtener el siguiente efecto de interfaz (por supuesto, descomparar la billetera de Baidu, no hay una imagen en la billetera de Baidu, por lo que debe encontrar una imagen aleatoria):