html текст
All interests
  • All interests
  • Design
  • Food
  • Gadgets
  • Humor
  • News
  • Photo
  • Travel
  • Video
Click to see the next recommended page
Like it
Don't like
Add to Favorites

Создаем живые обои для Android

Не буду разглагольствовать сильно много, а сразу буду говорить по делу.

Живые обои – это анимированные интерактивные обои для главного экрана Android, по сути они схожи с другими приложениями для Android и могут использовать тот же самый функционал API.
Чтобы создать собственные живые обои необходимо создать XML файл, содержащий описание приложения, кроме того в нем могут быть указано изображение предварительного просмотра и ссылка на активити настроек.




Любые живые обои создаются на основе сервиса WallpaperService который включает в себя ряд функций/методов которые мало чем отличаются от класса SurfaceView. Вот какие функции имеет класс WallpaperService:
  • onCreate()
  • onSurfaceCreated()
  • onVisibilityChanged()
  • onOffsetsChanged()
  • onTouchEvent()
  • onCommand()
Как и в разработке игр — в разработке обоев используется старый добрый Canvas на основе которого рисуются все возможные объекты. 

Для того что бы создать живые обои нужно обязательно в AndroidManifest'e указать наличие прав на «android.permission.BIND_WALLPAPER» и что наше приложение использует функционал android.software.live_wallpaper. Если этого не сделать, приложение сможет быть установлено на устройствах, которые не поддерживают живые обои, что не желательно. 

Создаем живые обои


Создаем проект — Eclipse — File — New — Android Project — NameProject. И убираем галочку «Create Activity», так как у нас нет активити — оно нам не нужно. Добавьте папку /res/xml и в него файл mywallpaper.xml. В этом файле будет содержаться описание ваших обоев и графика для предварительного просмотра. Этот файл ресурсов будет указан в файле AndroidManifest.xml. Если вы укажете атрибут android:thumbnail, указывающий на ресурс типа drawable, это даст возможность показать уменьшенное изображение ваших обоев.

Нам нужно внести изменения в манифест, открываем AndroidManifest, выделяем «Ctrl + A» и удаляем. Вставляем код который ниже:

AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest 
        xmlns:android="http://schemas.android.com/apk/res/android"
        package="live.wallpaper"
        android:versionCode="1"
        android:versionName="1.0">
        <application 
                android:icon="@drawable/ic_launcher" 
                android:label="@string/app_name">
                <service 
                        android:name="LiveWallpaperService"
                        android:enabled="true"
                        android:icon="@drawable/ic_launcher"
                        android:label="@string/app_name"
                        android:permission="android.permission.BIND_WALLPAPER">
                        <intent-filter android:priority="1" >
                                <action android:name="android.service.wallpaper.WallpaperService" />
                        </intent-filter>
                        <meta-data 
                                android:name="android.service.wallpaper" 
                                android:resource="@xml/mywallpaper" />
                </service>
                <activity 
                        android:label="@string/app_name" 
                        android:name=".LiveWallpaperSettings" 
                        android:theme="@android:style/Theme.Light.WallpaperSettings"
                        android:exported="true" 
                        android:configChanges="orientation"/>
        </application>
        <uses-sdk android:minSdkVersion="8" />
</manifest> 


Дальше нам нужно в созданный файл mywallpaper.xml внести данные о пред просмотре обоине которую пользователь будет устанавливать.
Вот как выглядит этот файл:

mywallpaper.xml
<?xml version="1.0" encoding="UTF-8"?>
<wallpaper 
        xmlns:android="http://schemas.android.com/apk/res/android"  
        android:thumbnail="@drawable/ic_launcher" 
        android:description="@string/description"
        android:settingsActivity="live.wallpaper.LiveWallpaperSettings"/>


Дальше берем вот эти изображения:


и закидываем в папку res/drawable, они нам понадобятся для красоты обоев :)

Создаем класс Bubble.java который будет задавать направление наших бульб.

package live.wallpaper;
import java.util.Random;
import android.graphics.Bitmap;
import android.graphics.Canvas;
public class Bubble
{
        /**Позиция по Х и У*/
        public int x;
        public int y;
        
        /**Выоста и ширина*/
        public int widht;
        public int height;
        
        /**Скорость*/
        public int speed;
        
        /**Угол полета*/
        public double angle;
        
        Bitmap bmp;
        LiveWallpaperPainting pm;
        
        /**Конструктор*/
        public Bubble(LiveWallpaperPainting pm, Bitmap bmp) {
                this.pm = pm;
                this.bmp = bmp;
                
                /**По "х" у нас будем появляться рандомно*/
                Random rnd = new Random(System.currentTimeMillis());
                this.y = 1000;
                this.x = rnd.nextInt(800);
                
                /**Скорость рандомная*/
                this.speed = rnd.nextInt(15 - 5) + 15;
                
                /**Задаем размер бульбашек*/
                this.widht = 75;
                this.height = 75;
                
                angle = getRandomAngle();
        }
        
        /**Движение объектов*/
        public void update() {
                y -= Math.abs(speed * Math.cos(angle));
                x -= Math.abs(speed * Math.sin(angle));
        }
        
        /**Задаем рандомный угол полета*/
        private int getRandomAngle() {
        Random rnd = new Random(System.currentTimeMillis());
        return rnd.nextInt(1) * 90 + 90 / 2 + rnd.nextInt(15) + 5;
    }
        
        /**Рисуем*/
        public void onDraw(Canvas c) {
                update();
                c.drawBitmap(bmp, x, y, null);
        }
        
        /**Проверка на столкновения*/
    public boolean isCollition(float x2, float y2) {
          return x2 > x && x2 < x + widht && y2 > y && y2 < y + height;
    }
}


Думаю из комментариев понятно что делаю функции и что какая переменная обозначает, если не понятно пишите в комментарии я объясню что к чему.
Далее создаем класс LiveWallpaperPainting.java который будет рисовать все что токо захотим. Он будет иметь следующий код:

package live.wallpaper;
import java.util.ArrayList;
import java.util.List;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Style;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class LiveWallpaperPainting extends Thread implements Runnable{

        private SurfaceHolder surfaceHolder;
        private Context context;
        
        /** Состояние потоков */
        private boolean wait;
        private boolean run;
        
        /** Выосота и ширина сцены */
        private int width;
        private int height;
        
        /**Скоре, достижение :)*/
        private int score = 0;

        /**Список бульбашек который будет бесконечным*/
        public List<Bubble> bubble = new ArrayList<Bubble>();
        
        /**Это если захотишь сделать что бы выводило спрайт после взрыва*/
        //private List<Boms> temps = new ArrayList<Boms>();

        //private Bitmap blood;
        
        /**Позиция нажатия на экран*/
        private float posX;
        private float posY;
        
        /**Объект рисовалки наших достижений*/
        private Paint mScorePaint;
        
        /**Фоновый рисунок*/
        private Bitmap bg;
        
        /**Бульбаки*/
        private Bitmap bubbles;
  
        /**Конструктор*/
        public LiveWallpaperPainting(SurfaceHolder surfaceHolder, Context context, int radius) {
                this.surfaceHolder = surfaceHolder;
                this.context = context;

                /**Запускаем поток*/
                this.wait = true;
                
                /*Рисуем всякое разное*/
                bubbles = BitmapFactory.decodeResource(context.getResources(), R.drawable.bubble);
                //blood = BitmapFactory.decodeResource(context.getResources(), R.drawable.blood1);
                bg = BitmapFactory.decodeResource(context.getResources(), R.drawable.bg);
                
             // стили для вывода счета
                mScorePaint = new Paint();
                mScorePaint.setTextSize(20);
                mScorePaint.setStrokeWidth(1);
                mScorePaint.setStyle(Style.FILL);
                mScorePaint.setColor(Color.WHITE);
        }

        /**
         * Ставим на паузу анимацию 
         */
        public void pausePainting() {
                this.wait = true;
                synchronized(this) {
                        this.notify();
                }
        }

        /**
         * Запускаем поток когда сняли с паузы
         */
        public void resumePainting() {
                this.wait = false;
                synchronized(this) {
                        this.notify();
                }
        }

        /**
         * Останавливаем поток
         */
        public void stopPainting() {
                this.run = false;
                synchronized(this) {
                        this.notify();
                }
        }

        
        /**Рисуем в потоке все наши рисунки*/
        public void run() {
                this.run = true;
                Canvas c = null;
                while (run) {
                        try {
                                c = this.surfaceHolder.lockCanvas(null);
                                synchronized (this.surfaceHolder) {
                                        Thread.sleep(50);
                                        bubble.add(new Bubble(this, bubbles));
                                        doDraw©;
                                }
                        } catch (InterruptedException e) {
                                                        e.printStackTrace();
                                                } finally {
                                if (c != null) {
                                        this.surfaceHolder.unlockCanvasAndPost©;
                                }
                        }
                        // pause if no need to animate
                        synchronized (this) {
                                if (wait) {
                                        try {
                                                wait();
                                        } catch (Exception e) {}
                                }
                        }
                }
        }

        /**
         * Растягиваем картинку под размер экрана
         */
        public void setSurfaceSize(int width, int height) {
                this.width = width;
                this.height = height;
                synchronized(this) {
                        this.notify();
                        bg = Bitmap.createScaledBitmap(bg, width, height, true);
                }
        }
        
        /**
         * Обрабатываем нажатия на экран
         */
        public boolean doTouchEvent(MotionEvent event) {
                posX = event.getX();
            posY = event.getY();
            synchronized (surfaceHolder) {
                   for (int i = bubble.size() - 1; i >= 0; i--) {
                          Bubble sprite = bubble.get(i);
                          if (sprite.isCollition(posX, posY)) {
                                    bubble.remove(sprite);
                                    score++;
                                //temps.add(new Boms(temps, this, blood, posX, posY));
                                break;
                          }
                   }
            }
            return true;
      }
        
        /**
         * Рисуем на сцене в потоке
         */
        private void doDraw(Canvas canvas) {
                        canvas.drawColor(Color.WHITE);
                        canvas.drawBitmap(bg, 0,0, null);
                        /*for (int i = temps.size() - 1; i >= 0; i--) {
                    temps.get(i).onDraw(canvas);
                        }*/
                        
                        for(Bubble bub: bubble) {
                                if(bub.y >= 0 || bub.x <= 0)
                                        bub.onDraw(canvas);
                                else
                                        bubble.remove(this);
                        }
                        
                    canvas.drawText("Score: " + score, 50, 70, mScorePaint);
        }        
        }


И так если Вы заметили то код мало отличается от кода по созданию игр, единственное отличие это то что мы рисуем сразу в потоке не раскошеливаясь на создание сцены с SurfaceView. 

Я забыл упомянуть что обоинау нас будет выглядеть вот так:


Теперь я думаю понятно что будет представлять из себя этот класс. В нем мы рисуем фон, рисуем бульбы и рисуем количество хлопнутых Вами бульбашек. 

Дальше создаем класс LiveWallpaperService, это наследник класса WallpaperService про которого я говорил в начале статьи. Он имеет следующий вид:

LiveWallpaperService.java
package live.wallpaper;
import java.util.ArrayList;
import java.util.List;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.service.wallpaper.WallpaperService;
import android.service.wallpaper.WallpaperService.Engine;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
public class LiveWallpaperService extends WallpaperService {

    public static final String PREFERENCES = "net.androgames.blog.sample.livewallpaper";
    public static final String PREFERENCE_RADIUS = "preference_radius";
    
    @Override
    public Engine onCreateEngine() {
            return new SampleEngine();
    }

    @Override
    public void onCreate() {
            super.onCreate();
    }

    @Override
    public void onDestroy() {
            super.onDestroy();
    }

    public class SampleEngine extends Engine implements SharedPreferences.OnSharedPreferenceChangeListener {

            private LiveWallpaperPainting painting;
            private SharedPreferences prefs;
            
            SampleEngine() {
                    SurfaceHolder holder = getSurfaceHolder();
                    prefs = LiveWallpaperService.this.getSharedPreferences(PREFERENCES, 0);
                    prefs.registerOnSharedPreferenceChangeListener(this);
                    painting = new LiveWallpaperPainting(holder, getApplicationContext(), 
                                    Integer.parseInt(prefs.getString(PREFERENCE_RADIUS, "10")));
            }

            public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
            }

            @Override
            public void onCreate(SurfaceHolder surfaceHolder) {
                    super.onCreate(surfaceHolder);
                    setTouchEventsEnabled(true);
            }

            @Override
            public void onDestroy() {
                    super.onDestroy();
                    // remove listeners and callbacks here
                    painting.stopPainting();
            }

            @Override
            public void onSurfaceChanged(SurfaceHolder holder, int format, int width, int height) {
                    super.onSurfaceChanged(holder, format, width, height);
                    painting.setSurfaceSize(width, height);
            }

            @Override
            public void onSurfaceCreated(SurfaceHolder holder) {
                    super.onSurfaceCreated(holder);
                    painting.start();
                    
            }


            @Override
            public void onVisibilityChanged(boolean visible) {
                    if (visible) {
                            painting.resumePainting();
                    } else {
                            // remove listeners and callbacks here
                            painting.pausePainting();
                    }
            }
            
            @Override
            public void onSurfaceDestroyed(SurfaceHolder holder) {
                    super.onSurfaceDestroyed(holder);
                    boolean retry = true;
                    painting.stopPainting();
                    while (retry) {
                            try {
                                    painting.join();
                                    retry = false;
                            } catch (InterruptedException e) {}
                    }
            }


            @Override
            public void onTouchEvent(MotionEvent event) {
                    super.onTouchEvent(event);
                    painting.doTouchEvent(event);
            }
            
    }
}


Методы OnCreate, OnDestroy, onVisibilityChanged, onSurfaceChanged, onSurfaceCreated и onSurfaceDestroyed вызываются, когда запускаем обои. Только с помощью этих методов, живые обои могут быть анимироваными.

На видео ниже показано чего мы добились, больбашки летят и при клике на них — убиваются, скоре записываются и если поставить их на рабочий стол то будет тот же эффект, если немного допилить со стороны дизайнера то вообще будет сказка. 
Читать дальше
Twitter
Одноклассники
Мой Мир

материал с dajver.blogspot.com

11

      Add

      You can create thematic collections and keep, for instance, all recipes in one place so you will never lose them.

      No images found
      Previous Next 0 / 0
      500
      • Advertisement
      • Animals
      • Architecture
      • Art
      • Auto
      • Aviation
      • Books
      • Cartoons
      • Celebrities
      • Children
      • Culture
      • Design
      • Economics
      • Education
      • Entertainment
      • Fashion
      • Fitness
      • Food
      • Gadgets
      • Games
      • Health
      • History
      • Hobby
      • Humor
      • Interior
      • Moto
      • Movies
      • Music
      • Nature
      • News
      • Photo
      • Pictures
      • Politics
      • Psychology
      • Science
      • Society
      • Sport
      • Technology
      • Travel
      • Video
      • Weapons
      • Web
      • Work
        Submit
        Valid formats are JPG, PNG, GIF.
        Not more than 5 Мb, please.
        30
        surfingbird.ru/site/
        RSS format guidelines
        500
        • Advertisement
        • Animals
        • Architecture
        • Art
        • Auto
        • Aviation
        • Books
        • Cartoons
        • Celebrities
        • Children
        • Culture
        • Design
        • Economics
        • Education
        • Entertainment
        • Fashion
        • Fitness
        • Food
        • Gadgets
        • Games
        • Health
        • History
        • Hobby
        • Humor
        • Interior
        • Moto
        • Movies
        • Music
        • Nature
        • News
        • Photo
        • Pictures
        • Politics
        • Psychology
        • Science
        • Society
        • Sport
        • Technology
        • Travel
        • Video
        • Weapons
        • Web
        • Work

          Submit

          Thank you! Wait for moderation.

          Тебе это не нравится?

          You can block the domain, tag, user or channel, and we'll stop recommend it to you. You can always unblock them in your settings.

          • dajver
          • домен dajver.blogspot.com
          • домен blogspot.com

          Get a link

          Спасибо, твоя жалоба принята.

          Log on to Surfingbird

          Recover
          Sign up

          or

          Welcome to Surfingbird.com!

          You'll find thousands of interesting pages, photos, and videos inside.
          Join!

          • Personal
            recommendations

          • Stash
            interesting and useful stuff

          • Anywhere,
            anytime

          Do we already know you? Login or restore the password.

          Close

          Add to collection

             

            Facebook

            Ваш профиль на рассмотрении, обновите страницу через несколько секунд

            Facebook

            К сожалению, вы не попадаете под условия акции