English | 简体中文 | 繁體中文 | Русский язык | Français | Español | Português | Deutsch | 日本語 | 한국어 | Italiano | بالعربية
Croire que chacun d'entre nous a joué à des jeux de puzzle pendant notre enfance, aujourd'hui, avec la généralisation des téléphones mobiles, un nombre croissant de jeux est jouable sur les téléphones mobiles, donc, pour relire notre enfance, j'ai écrit ce jeu de puzzle simple, et cela peut également approfondir certaines connaissances de base d'Android.
Comme d'habitude, d'abord le visuel :
Ici, pour illustrer l'effet, j'ai très peu désorganisé les images, ce qui peut être modifié dans le code.
Tout d'abord, il y a une image par défaut, qui peut être utilisée pour assembler le puzzle, ou vous pouvez choisir l'image de votre choix pour assembler le puzzle, le processus de puzzle enregistre le nombre de mouvements, et un message de sourire apparaît lorsque le jeu est gagné, indiquant la victoire et le nombre de mouvements utilisés.
ps : ceux qui sont intéressés peuvent continuer à l'étendre ici, par exemple, ajouter des options de difficulté de jeu, diviser l'image en plus petits carrés, etc.
Idée générale : découper la grande image en petits carrés, enregistrer les informations de chaque petit carré dans un tableau, afficher chaque petit carré avec un GridLayout, et marquer un petit carré comme une case vide (la case vide peut être échangée avec des cases adjacentes), ajouter des événements de clic et des événements de gestes sur chaque petit carré du GridLayout et sur tout l'écran, chaque fois qu'il y a un clic ou un geste, vérifier si le petit carré peut être déplacé, et enfin afficher un message de victoire lorsque le jeu est gagné.
Pas de temps à perdre, passons directement à la mise en œuvre étape par étape du processus de puzzle game.
1.Classe relative aux petits carrés.
C'est un ensemble de variables, de classes et de méthodes Setter et Getter pour chaque petit carré, utilisé pour gérer les informations de chaque petit carré découpé de la grande image. C'est simple, juste des variables et des méthodes Setter et Getter, voici le code~
/** * Created by yyh on 2016/10/21. */ public class GameItemView{ /** * Les informations de chaque petit carré */ //La position réelle de chaque petit carré en x, private int x=0; //La position réelle de chaque petit carré en y, private int y=0; //L'image de chaque petit carré, private Bitmap bm; //La position de l'image de chaque petit carré en x, private int p_x=0; //La position de l'image de chaque petit carré en y. private int p_y=0; public GameItemView(int x, int y, Bitmap bm) { super(); this.x = x; this.y = y; this.bm = bm; this.p_x=x; this.p_y=y; } public int getX() { return x; } public void setX(int x) { this.x = x; } public int getY() { return y; } public Bitmap getBm() { return bm; } public void setBm(Bitmap bm) { this.bm = bm; } public int getP_x() { return p_x; } public void setP_x(int p_x) { this.p_x = p_x; } public int getP_y() { return p_y; } public void setP_y(int p_y) { this.p_y = p_y; } /** * Vérifier si la position de chaque petit carré est correcte * @return */ public boolean isTrue(){ if (x==p_x&&y==p_y){ return true; } return false; } }
2.La mise en page de l'interface principale
L'interface principale est simple, un bouton pour changer l'image, une ImageView pour afficher l'image originale, un GridLayout pour jouer au puzzle game, et enfin, un TextView pour afficher le nombre de pas nécessaires pour terminer ce puzzle. La mise en page est la suivante :
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" > <LinearLayout android:id="@"+id/ll" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal" > <Button android:id="@"+id/bt_choice" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Choisir une image" android:adjustViewBounds="true" /> </LinearLayout> <ImageView android:id="@"+id/iv" android:layout_below="@id/ll" android:adjustViewBounds="true" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/haizei" android:layout_marginTop="3dp" ></ImageView> !-- l'interface principale du jeu--> <GridLayout android:layout_marginTop="3dp" android:layout_below="@id/iv" android:id="@"+id/gl" android:layout_width="wrap_content" android:layout_height="wrap_content" android:columnCount="5" android:rowCount="3" android:adjustViewBounds="true" > </GridLayout> <TextView android:id="@"+id/tv_step" android:layout_below="@id/gl" android:layout_marginTop="3dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="已用步数:0" android:textSize="26sp" /> </RelativeLayout>
3.Ouvrir l'image et sélectionner une image
Pour configurer l'événement de clic sur le bouton, appeler la méthode startActivityForResult(Intent intent, int requestCode); pour obtenir une image.
bt_choice.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent= new Intent("android.intent.action.GET_CONTENT"); intent.setType("image",/* startActivityForResult(intent, CHOICE_PHOTO);//ouvrir l'album } });
Redéfinir la méthode onActivityResult(int requestCode, int resultCode, Intent data) dans l'Activity pour afficher l'image sélectionnée et initialiser le jeu. (Après avoir sélectionné l'image, il faut procéder à la coupe de l'image et au début du jeu de puzzle.)
protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); switch (requestCode){ case CHOICE_PHOTO: if (resultCode == RESULT_OK){ //vérifier la version du système d'exploitation du téléphone if (Build.VERSION.SDK_INT >=19){ handleImageOnKitKat(data); //obtenir l'image dans l'imageview BitmapDrawable bitmapDrawable = (BitmapDrawable) photo.getDrawable(); bt_tupan = bitmapDrawable.getBitmap(); //retirer les petits carrés du GridLayout existant, removeGameItem(); //couper la nouvelle image en petits carrés et l'ajouter à GridLayout. setGameItem(); //commencer le jeu startGame(); }else { handleImageBeforeKitKat(data); //obtenir l'image dans l'imageview BitmapDrawable bitmapDrawable = (BitmapDrawable) photo.getDrawable(); bt_tupan = bitmapDrawable.getBitmap(); //retirer les petits carrés du GridLayout existant, removeGameItem(); //couper la nouvelle image en petits carrés et l'ajouter à GridLayout. setGameItem(); //commencer le jeu startGame(); } } } }
Ensuite, voici la fonction d'implémentation de la méthode spécifique pour choisir l'image. Les commentaires sont clairs, sans entrer dans les détails. Notre point focal est l'implémentation détaillée des puzzles et des gestes. Il y a de nombreuses manières de choisir une image. Sans plus attendre, il existe des frameworks prêts à l'emploi sur le web.
//le téléphone n'est pas supérieur à19de la méthode de récupération des données private void handleImageBeforeKitKat(Intent data) { Uri uri = data.getData(); String imagePath = getImagePath(uri, null); displayImage(imagePath); } /** * le téléphone est supérieur à19de la méthode de récupération des données * @param data */ @TargetApi(Build.VERSION_CODES.KITKAT) private void handleImageOnKitKat(Intent data) { String imagePath=null; Uri uri=data.getData(); if (DocumentsContract.isDocumentUri(this,uri)){ //Si l'url est de type document, traiter l'id du document. String docId=DocumentsContract.getDocumentId(uri); if ("com.android.providers.media.documents".equals(uri.getAuthority())){ String id =docId.split(":")[1];//Extraire l'id sous forme numérique; String selection= MediaStore.Images.Media._ID+"="+id; imagePath=getImagePath(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,selection); }else if ("com.android.providers.downloads.documents".equals(uri.getAuthority())){ Uri contenturi= ContentUris.withAppendedId(Uri.parse("content:",//downloads/public_downloads"),Long.valueOf(docId)); imagePath=getImagePath(contenturi,null); } }else if ("content".equalsIgnoreCase(uri.getScheme())){ //Si l'uri n'est pas de type document, traiter de manière ordinaire. imagePath=getImagePath(uri,null); } displayImage(imagePath); } /** * Affichage de l'image * @param imagePath //L'image du chemin. */ private void displayImage(String imagePath) { if (imagePath != null) { Bitmap bitmap = BitmapFactory.decodeFile(imagePath); if (isHeigthBigWidth(bitmap)) { Bitmap bt = rotaingImageView(bitmap);//tourner l'image90 degrés. Bitmap disbitmapt = ajustBitmap(bt); photo.setImageBitmap(disbitmapt); } else { Bitmap disbitmap = ajustBitmap(bitmap); photo.setImageBitmap(disbitmap); } } } /** * ajuster l'orientation de l'image * @param bitmap * @return */ private Bitmap rotaingImageView(Bitmap bitmap) { //action de rotation d'image Matrix matrix = new Matrix();; matrix.postRotate(270); // créer une nouvelle image Bitmap resizedBitmap = Bitmap.createBitmap(bitmap, 0, 0, bitmap.getWidth(), bitmap.getHeight(), matrix, true); return resizedBitmap; } /** * obtenir le chemin d'accès à l'image * @param externalContentUri * @param selection * @return */ private String getImagePath(Uri externalContentUri, String selection) { String path = null; Cursor cursor = getContentResolver().query(externalContentUri, null, selection, null, null); if (cursor != null) { if (cursor.moveToFirst()) { path = cursor.getString(cursor.getColumnIndex(MediaStore.Images.Media.DATA)); } } cursor.close(); return path; }
4. Le processus de formation des petits carrés du puzzle.}}
Regardant les petits carrés, utiliser GridLayout est le plus pratique. Donc, utiliser un GridLayout pour afficher les petits carrés coupés de la grande image, utiliser un tableau d'ImageView pour enregistrer les informations des petits carrés, et par défaut, définir le dernier petit carré comme un carré vide.
Tout d'abord, les variables nécessaires. Les commentaires sont clairs.
/** * Créer plusieurs petits cadres de jeu à l'aide d'un tableau binaire */ private ImageView [][] iv_game_arr=new ImageView[3][5]; /** *Interface principale du jeu * */ private GridLayout gl_game_layout; //Lignes et colonnes des petits carrés private int i; private int j; /**Variable globale pour le carré vide*/ private ImageView iv_null_imagview;
Ensuite, il s'agit de récupérer l'image à partir d'Imageview et de couper l'image suivant un certain nombre de lignes et de colonnes (ici, le puzzle est réglé pour3rang5Colonne). Enregistrer les informations des petits carrés coupés dans un tableau d'ImageView. Définir un Tag et un écouteur d'événement de clic pour chaque petit carré.
private void setGameItem() { //Ajuster la taille de l'image Bitmap abitmap=ajustBitmap(bt_tupan); int ivWidth=getWindowManager().getDefaultDisplay().getWidth()/5;//Largeur et hauteur de chaque petit carré de jeu. Couper en carré int tuWidth=abitmap.getWidth()/5; for (int i=0;i<iv_game_arr.length;i++){ for (int j=0;j<iv_game_arr[0].length;j++){ //Diviser la grande image en petits carrés Bitmap bm=Bitmap.createBitmap(abitmap,j*tuWidth,i*tuWidth,tuWidth,tuWidth); iv_game_arr[i][j]=new ImageView(this); iv_game_arr[i][j].setImageBitmap(bm);//Définir le motif de chaque petit carré iv_game_arr[i][j].setLayoutParams(new RelativeLayout.LayoutParams(ivWidth, ivWidth)); //Définir l'intervalle entre les carrés iv_game_arr[i][j].setPadding(2, 2, 2, 2); iv_game_arr[i][j].setTag(new GameItemView(i, j, bm)); //Lié aux données personnalisées iv_game_arr[i][j].setOnClickListener(new View.OnClickListener() { ....... );
Bien sûr, les images que nous choisissons ne peuvent pas toutes être de tailles standard, donc, avant de couper l'image, nous devons l'ajuster. Ajuster l'image à5:3de proportion. (Ainsi, après coupure,3rang5Seulement les petits carrés de la colonne peuvent être coupés correctement) ici, je calcule à l'avance l'intervalle entre chaque petit carré pour width.
//Ajuster la taille de l'image private Bitmap ajustBitmap(Bitmap bitmap) { int width=getWindowManager().getDefaultDisplay().getWidth()-(iv_game_arr[0].length-1)*2; int heigth=width/5*3; Bitmap scaledBitmap=Bitmap.createScaledBitmap(bitmap, width, heigth, true); return scaledBitmap; }
Placer chaque petit carré dans le GridLayout.
/** * Placer les petits carrés dans le GridLayout */ private void startGame() { tv_step.setText("Nombre de pas utilisés : 0"); for (i = 0; i <iv_game_arr.length; i++){ for (j = 0; j <iv_game_arr[0].length; j++){ gl_game_layout.addView(iv_game_arr[i][j]); } } //Définir le dernier carré en tant que carré vide défini. setNullImageView(iv_game_arr[i-1][j-1]);
5. Processus de clic et de jugement des gestes des petits carrés
C'est le cœur du jeu de puzzle, comprendre les règles de déplacement et de changement des petits carrés, c'est aussi comprendre le jeu de puzzle.
Pour l'événement de clic, d'abord obtenir diverses informations du carré cliqué (position, motif) et des informations de position du carré vide, juger si le carré cliqué est adjacent au carré vide, si oui, échanger les données de déplacement (en utilisant TranslateAnimation pour réaliser l'animation de déplacement), sinon pas d'opération.
a. Méthode de jugement de l'adjacence entre le carré cliqué et le carré vide
/** * Juger si le carré cliqué actuel est adjacent à un carré vide. * @param imageView Le carré cliqué actuel * @return true : adjacent. false : non adjacent. */ public boolean isAdjacentNullImageView(ImageView imageView){ //Obtenir la position actuelle du carré vide et la position du carré cliqué GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag(); GameItemView now_gameItem_view = (GameItemView) imageView.getTag(); if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()+1==null_gameItemView.getX()){//Le bloc cliqué est au-dessus du bloc vide return true; }else if(null_gameItemView.getY()==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX()+1){//Le bloc cliqué est en dessous du bloc vide return true; }else if(null_gameItemView.getY()==now_gameItem_view.getY()+1&&now_gameItem_view.getX()==null_gameItemView.getX()){//Le bloc cliqué est à gauche du bloc vide return true; }else if(null_gameItemView.getY()+1==now_gameItem_view.getY()&&now_gameItem_view.getX()==null_gameItemView.getX(){ ////Le bloc cliqué est à droite du bloc vide return true; } return false; }
b. Ensuite, si les carrés sont adjacents, entrez dans la méthode d'échange de données du carré
Il y a une méthode de surcharge ici, animation ou non. Les échanges de données sans animation sont prévus pour le mélange des pièces du jeu à l'initialisation. Voici le code de remplacement principal. Après chaque échange, il faut vérifier si le jeu est gagné (c'est-à-dire si le puzzle est terminé~).
//Obtenir les données du carré cliqué lié GameItemView gameItemView = (GameItemView) itemimageView.getTag(); //Définir le motif du carré vide en tant que carré cliqué iv_null_imagview.setImageBitmap(gameItemView.getBm()); //Obtenir les données du carré vide lié GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag(); //Échanger des données (transférer les données du bloc cliqué au bloc vide)} null_gameItemView.setBm(gameItemView.getBm()); null_gameItemView.setP_x(gameItemView.getP_x()); null_gameItemView.setP_y(gameItemView.getP_y()); //Définir le bloc cliqué comme bloc vide. setNullImageView(itemimageView); if (isStart){ isGameWin();//Lorsque cela réussit, une boîte de dialogue contextuelle apparaîtra. }
c.les paramètres d'animation lors de l'échange
Lorsque l'animation est configurée, d'abord juger la direction de déplacement, configurer une animation de déplacement différente selon la direction, puis écouter la fin de l'animation, effectuer des opérations d'échange de données. C'est-à-dire que après b., si les blocs adjacents entrent dans la méthode d'échange de données de bloc, puis exécuter l'animation.
//1.créer une animation, configurer la direction, la distance de déplacement //juger la direction, configurer l'animation if (itemimageView.getX()>iv_null_imagview.getX()){//Le bloc cliqué est au-dessus du bloc vide //descendre translateAnimation = new TranslateAnimation(0.1f,-itemimageView.getWidth(),0.1f,0.1f); }else if (itemimageView.getX()<iv_null_imagview.getX()){//Le bloc cliqué est en dessous du bloc vide //monter boolean f=itemimageView.getX()<iv_null_imagview.getX(); //Log.i("click block","sssssssssssssssssssssssss"+f); translateAnimation = new TranslateAnimation(0.1f,itemimageView.getWidth(),0.1f,0.1f); }else if (itemimageView.getY()>iv_null_imagview.getY()){//Le bloc cliqué est à gauche du bloc vide //déplacer à droite translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,-itemimageView.getWidth()); else if(itemimageView.getY()<iv_null_imagview.getY()){//Le bloc cliqué est à droite du bloc vide //Déplacer vers la gauche translateAnimation=new TranslateAnimation(0.1f,0.1f,0.1f,itemimageView.getWidth()); } //2.Définir divers paramètres d'animation translateAnimation.setDuration(80); translateAnimation.setFillAfter(true); //3.Définir l'écouteur d'animation translateAnimation.setAnimationListener(new Animation.AnimationListener() { @Override public void onAnimationStart(Animation animation) { isAminMove=true; } @Override public void onAnimationEnd(Animation animation) { //La fin de l'animation, échanger les données ...... } //L'exécution de l'animation itemimageView.startAnimation(translateAnimation);
La procédure de clic est terminée, passons à l'événement de détection des gestes. C'est-à-dire que non seulement vous pouvez déplacer le carré en cliquant dessus, mais vous pouvez également le déplacer avec des gestes.
One. Créer un objet gestuelle
Effectuer les opérations liées aux gestes dans la méthode onFling.
//Créer un objet gestuelle gestureDetector =new GestureDetector(this, new GestureDetector.OnGestureListener() { @Override public boolean onDown(MotionEvent e) { return false; } @Override public void onShowPress(MotionEvent e) { } @Override public boolean onSingleTapUp(MotionEvent e) { return false; } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { return false; } @Override public void onLongPress(MotionEvent e) { } @Override public boolean onFling(MotionEvent e1, MotionEvent e2float velocityX, float velocityY) { //Opérations liées aux gestes ...... }
Puis nous faisons des opérations spécifiques dans la méthode onFling
Deux. Déterminer la direction du déplacement du geste
Obtenir différentes directions de déplacement en fonction de différentes valeurs de retour.
/** * Augmenter le glissement du geste, déterminer si le glissement du geste est vertical ou horizontal * @param start_x Point de départ du geste en x * @param start_y Point de départ du geste en y * @param end_x Point final du geste en x * @param end_y Point final du geste en y * @return 1Haut 2Bas 3Gauche 4Droite */ public int getDirctionByGesure(float start_x,float start_y,float end_x,float end_y){ boolean isLeftOrRight =(Math.abs(end_x-start_x)>Math.abs(end_y-start_y))?true:false; //Est-ce que c'est une direction latérale if(isLeftOrRight){//Gauche et droite boolean isLeft=(end_x-start_x)>0?false:true; if(isLeft){ return 3; }else { return 4; } }else{//Haut et bas boolean isUp=(end_y-start_y)>0?false:true; if (isUp){ return 1; }else { return 2; } } }
Trois. Déterminer si le déplacement est possible en fonction du bloc vide et de la direction du déplacement, puis procéder au déplacement.
Comme c'est un geste, le déplacement doit certainement être des blocs autour du bloc vide, donc la clé est de déterminer la direction du bloc vide à déplacer, puis de déterminer si le déplacement est possible en fonction de la direction, puis de procéder au déplacement. (La méthode changeDateByImageView() est l'opération spécifique de données d'échange et de déplacement de blocs. C'est la méthode de l'événement de clic.)
/**Redéfinir la méthode changeByDirGes(int type); * Déplacer les blocs adjacents au bloc vide en fonction de la direction du geste. * @param type Valeur de retour de la direction 1Haut 2Bas 3Gauche 5Droite * @param isAnim Si il y a une animation true: il y a une animation, false: il n'y a pas d'animation */ public void changeByDirGes(int type,boolean isAnim){ //1Obtenir la position actuelle du bloc vide. GameItemView null_gameItemView = (GameItemView) iv_null_imagview.getTag(); int new_x=null_gameItemView.getX(); int new_y=null_gameItemView.getY(); //2Selon la direction, définir les coordonnées des positions adjacentes correspondantes. if (type==1){//Cela signifie que le bloc vide est au-dessus du bloc à déplacer. new_x++; }else if (type==2){//Le bloc vide est en dessous du bloc à déplacer new_x--; }else if (type==3){//Le bloc vide est à gauche du bloc à déplacer new_y++; }else if (type==4){//Le bloc vide est à droite du bloc à déplacer new_y--; } //3Juger de l'existence de cette nouvelle coordonnée if(new_x>=0&&new_x<iv_game_arr.length&&new_y>=0&&new_y<iv_game_arr[0].length){ //Il existe, peut être déplacé et échanger des données if(isAnim){//Il y a une animation changeDateByImageView(iv_game_arr[new_x][new_y]); }else{ changeDateByImageView(iv_game_arr[new_x][new_y],isAnim); } }else{ //Ne rien faire } }
Très bien, l'événement de geste est terminé avec succès~
Il y a deux points à noter ici.1Tout d'abord, définir la méthode onTouchEvent() de l'Activity actuelle, transférer l'événement de toucher à la gestion des gestes, puis également définir la méthode dispatchTouchEvent(), dans laquelle il faut également transférer l'événement de geste vers le bas, sinon sans transférer l'événement de geste vers le bas, dans le GridLayout, seul l'événement de clic peut être déclenché et l'événement de geste ne fonctionne pas.2Doit ajouter un drapeau pour indiquer si l'objet est en train de se déplacer. Si l'objet est en train de se déplacer, ne rien faire, sinon à chaque clic sur le petit bloc, même pendant le déplacement, cela déclenche l'événement de clic et déclenche à nouveau le déplacement d'animation, ce qui peut entraîner une mauvaise expérience utilisateur.
@Override public boolean onTouchEvent(MotionEvent event) { return gestureDetector.onTouchEvent(event); } @Override public boolean dispatchTouchEvent(MotionEvent ev) { gestureDetector.onTouchEvent(ev); return super.dispatchTouchEvent(ev); }
6Méthode pour mélanger les blocs au début du jeu et afficher un Toast à la fin du jeu.
Le code est simple, mettons directement le code, dont le Toast pop est un Toast avec une animation personnalisée View.
//Mélanger l'ordre des images de manière aléatoire public void randomOrder(){ //Nombre de désordres, pour faciliter les tests, il est réglé très petit. for (int i=0;i<5;i++){ //Échanger des données selon le geste, sans animation. int type = (int) (Math.random()*4)+1; // Log.i("sssssssssfdfdfd", "Nombre d'échanges"+i+"valeur de type"+type); changeByDirGes(type, false); } } /** * Méthode de jugement de la fin du jeu */ public void isGameWin(){ //Indicateur de victoire du jeu boolean isGameWin =true; //Parcourir chaque petit carré for (i = 0; i <iv_game_arr.length; i++){ for (j = 0; j <iv_game_arr[0].length; j++){ //Ne pas juger des carrés vides, sauter if (iv_game_arr[i][j]==iv_null_imagview){ continue; } GameItemView gameItemView= (GameItemView) iv_game_arr[i][j].getTag(); if (!gameItemView.isTrue()){ isGameWin=false; //Sortir de la boucle interne break; } } if (!isGameWin){ //Sortir de la boucle externe break; } } //Selon une variable commutatrice, jugez si le jeu est terminé, et donnez un提示when it is. if (isGameWin){ // Toast.makeText(this, "Victoire de jeu", Toast.LENGTH_SHORT).show(); ToastUtil.makeText(this, "Félicitations, vous avez gagné le jeu, il a fallu ",+step+"étape", ToastUtil.LENGTH_SHORT, ToastUtil.SUCCESS); step=0; } }
Très bien, la partie importante est terminée, il y a encore un Toast personnalisé View ici, une explication détaillée du Toast sera dans l'article suivant, ici nous expliquons simplement le processus d'implémentation du Toast personnalisé.
Tout d'abord, créez une classe SuccessToast (le sourire inclut l'œil gauche, l'œil droit et l'arc du sourire). Nous fournissons le processus central. Utilisons l'animation pour réaliser le processus de dessin dynamique du sourire.
@Override protected void onDraw(Canvas canvas) {}} super.onDraw(canvas); mPaint.setStyle(Paint.Style.STROKE); //Dessiner l'arc de sourire canvas.drawArc(rectF, 180, endAngle, false, mPaint); mPaint.setStyle(Paint.Style.FILL); if (isSmileLeft) { //Si c'est un œil gauche, dessiner l'œil gauche canvas.drawCircle(mPadding + mEyeWidth + mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint); } if (isSmileRight) { //Si il y a un œil, dessiner l'œil droit. canvas.drawCircle(mWidth - mPadding - mEyeWidth - mEyeWidth / 2, mWidth / 3, mEyeWidth, mPaint); } } /** * Méthode de début de l'animation * @param startF Valeur de début * @param endF Valeur de fin * @param time Durée de l'animation * @return */ private ValueAnimator startViewAnim(float startF, final float endF, long time) { //Configurer les valeurs de début et de fin de valueAnimator. valueAnimator = ValueAnimator.ofFloat(startF, endF); //Configurer la durée de l'animation valueAnimator.setDuration(time); //Configurer l'interpolateur. Contrôler la vitesse de variation de l'animation valueAnimator.setInterpolator(new LinearInterpolator()); //Configurer l'écouteur. Écouter les changements de valeur de l'animation et agir en conséquence. valueAnimator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { mAnimatedValue = (float) valueAnimator.getAnimatedValue(); //si la valeur de value est inférieure à 0.5 if (mAnimatedValue < 0.5) { isSmileLeft = false; isSmileRight = false; endAngle = -360 * (mAnimatedValue); //si la valeur de value est comprise entre 0.55et 0.7entre } else if (mAnimatedValue > 0.55 && mAnimatedValue < 0.7) { endAngle = -180; isSmileLeft = true; isSmileRight = false; //autres } else { endAngle = -180; isSmileLeft = true; isSmileRight = true; } //redessiner postInvalidate(); } }); if (!valueAnimator.isRunning()) { valueAnimator.start(); } return valueAnimator; }
Ensuite, créez un fichier success_toast_layout.xml pour terminer la mise en page de toast. La mise en page est de gauche à droite (une vue de sourire à gauche, un TextView d'indication à droite).
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:id="@"+id/root_layout" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="#00000000" android:orientation="vertical"> <LinearLayout android:id="@"+id/base_layout" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginBottom="25dp" android:layout_marginLeft="30dp" android:layout_marginRight="30dp" android:layout_marginTop="25dp" android:background="@drawable"/background_toast" android:orientation="horizontal"> <LinearLayout android:id="@"+id/linearLayout" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center"> <com.example.yyh.puzzlepicture.activity.Util.SuccessToast android:id="@"+id/successView" android:layout_width="50dp" android:layout_height="50dp" android:layout_gravity="center_vertical|left" android:layout_margin="10px" android:gravity="center_vertical|left" /> </LinearLayout> <TextView android:id="@"+id/toastMessage" android:layout_width="match_parent" android:layout_height="wrap_content" android:gravity="center_vertical" android:padding="10dp" android:text="New Text" /> </LinearLayout> </LinearLayout>
最后新建一个ToastUtil类,管理自定义的Toast.
/** * Created by yyh on 2016/10/25. */ public class ToastUtil { public static final int LENGTH_SHORT = 0; public static final int LENGTH_LONG = 1; public static final int SUCCESS = 1; static SuccessToast successToastView; public static void makeText(Context context, String msg, int length, int type) { Toast toast = new Toast(context); switch (type) { case 1: { View layout = LayoutInflater.from(context).inflate(R.layout.success_toast_layout, null, false); TextView text = (TextView) layout.findViewById(R.id.toastMessage); text.setText(msg); successToastView = (SuccessToast) layout.findViewById(R.id.successView); successToastView.startAnim(); text.setBackgroundResource(R.drawable.success_toast); text.setTextColor(Color.parseColor("#FFFFFF")); toast.setView(layout); break; } } toast.setDuration(length); toast.show(); } }
Ainsi, vous pouvez appeler ce Toast personnalisé dans ManiActivity.
Bien, terminé.
Code source du jeu :Jeu de puzzleprocessus de réalisation
gitHub:Jeu de puzzle.
Voici la totalité du contenu de cet article, j'espère qu'il vous aidera dans vos études et que vous soutiendrez également le tutoriel de cri.
Déclaration : le contenu de cet article est tiré du réseau, propriété de l'auteur original, contribué et téléchargé par les utilisateurs d'Internet. Le site web ne détient pas de droits de propriété, n'a pas été édité par l'homme et n'assume aucune responsabilité juridique. Si vous trouvez du contenu suspect de violation de droits d'auteur, veuillez envoyer un e-mail à notice#w.3Pour signaler une violation, veuillez envoyer un e-mail à codebox.com (remplacez # par @) et fournir des preuves pertinentes. Une fois vérifié, le site supprimera immédiatement le contenu suspect de violation de droits d'auteur.