Menciptakan efek aliran Cover menggunakan Flash dan AS3
() translation by (you can also view the original English article)
Anda sudah pasti melihat tampilan "Cover Flow" efek. Itu adalah seluruh tempat pada hal-hal Apple. Dan Anda juga mungkin telah melihat sejumlah implementasi Cover Flow di Flash. Dalam tutorial ini, Anda akan mendapatkan satu lagi. Kami akan memanfaatkan kemampuan 3D built-in Flash Player 10 (yang pra-Stage3D) dan membangun versi kita sendiri berbasis XML Cover Flow.
Catatan: Tutorial ini awalnya diterbitkan pada bulan April 2011 - sebelum Stage3D dirilis - sebagai freebie untuk pelanggan newsletter kami. Karena Activetuts + telah sekarang ditutup, kami membuatnya gratis untuk semua pembaca.
Hasil akhir Tinjauan
Periksa demo untuk melihat apa yang kita sedang bekerja menuju.
Langkah 1: Buat File Flash ActionScript 3
Hal pertama yang harus dilakukan adalah membuat file Flash di mana kami akan bekerja. Membuka Flash CS4 atau CS5 dan pilih File > baru, dan pilih Flash File (ActionScript 3.0), dan tekan OK. Simpan file ini ke folder yang akan didedikasikan untuk proyek ini.



Aku akan menetapkan ukuran panggung untuk 600 x 400. Merasa bebas untuk menggunakan ukuran apa pun yang Anda inginkan, tapi saya akan merekomendasikan 600 x 400 sebagai minimum, mengingat bahwa memainkannya efek terbaik ketika memiliki banyak ruang untuk menampilkan itu sendiri. Juga, memilih tingkat bingkai cukup tinggi, seperti default 24. Ini akan membuat animasi yang halus.



Simpan file ini sebagai CoverFlow.fla dalam folder Anda dapat mendedikasikan untuk proyek ini.
Langkah 2: Buat dokumen kelas eksperimen
Tujuan kami akan membuat kelas memainkannya dapat digunakan kembali, tetapi untuk mengembangkan itu kita perlu tempat untuk tinggal. Kita akan menggunakan file Flash kami hanya dibuat untuk bertindak sebagai tanah pengujian untuk memainkannya kelas seperti yang kita mengembangkan itu, dan begitu kita akan membutuhkan dokumen kelas untuk pergi dengan Flash file. Kelas ini akan berfungsi untuk menyediakan tempat untuk instantiate dan menguji kelas memainkannya. Ini akan, dengan demikian, memberikan contoh bagaimana menggunakan kelas memainkannya setelah lengkap.
Di dalam editor teks pilihan Anda, buat sebuah file baru dan Simpan sebagai CoverFlowTest.as dalam folder yang sama sebagai file Flash Anda.

Tulisan rintisan keluar kelas sederhana:
1 |
|
2 |
package { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.events.*; |
6 |
import flash.net.*; |
7 |
import flash.utils.*; |
8 |
|
9 |
public class CoverFlowTest extends Sprite { |
10 |
|
11 |
public function CoverFlowTest() { |
12 |
trace("CoverFlowTest"); |
13 |
}
|
14 |
|
15 |
|
16 |
}
|
17 |
|
18 |
}
|
Ini tidak berbuat banyak, tetapi akan melacak pesan jika itu dihubungkan dengan benar, yang akan kita lakukan selanjutnya.
Langkah 3: Kawat kelas dokumen ke FLA
Dalam Flash file, klik di suatu tempat di panggung kosong, dan membuka panel properti (perintah/kontrol-F3, atau jendela > Properties). Di bidang kelas, ketik CoverFlowTest untuk menetapkan kelas dokumen.
Uji film Anda sekarang, dan Anda akan melihat jejak tersebut.



Step 4: Membuat kelas memainkannya
Selanjutnya kami akan membuat file untuk kelas memainkannya. Ini akan hidup dalam sebuah paket, jadi pertama menciptakan struktur folder. Mulai dalam folder proyek (pada tingkat yang sama sebagai FLA Anda), membuat sebuah folder bernama com. Dalam itu, membuat folder lain yang disebut tutsplus. Dalam hal ini, buat satu folder lain yang disebut memainkannya.
Sekarang membuat file teks lain yang disebut CoverFlow.as dalam folder memainkannya.



Tambahkan boilerplate berikut:
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.text.*; |
9 |
import flash.utils.*; |
10 |
|
11 |
public class CoverFlow extends Sprite { |
12 |
|
13 |
public function CoverFlow() { |
14 |
trace("CoverFlow"); |
15 |
}
|
16 |
|
17 |
}
|
18 |
|
19 |
}
|
Hal ini sangat mirip dengan kelas dokumen, kita hanya sedang mengantisipasi kebutuhan untuk lebih kelas, sehingga ada lebih pernyataan impor. Kelas ini juga akan memperpanjang Sprite, sehingga kami dapat mengobati memainkannya sebagai objek tampilan.
Step 5: Membuat sebuah Instance memainkannya
Sekarang untuk memastikan bahwa kami dapat menciptakan dan bekerja dengan memainkannya dalam kelas dokumen kami. Kembali di CoverFlowTest.as, mengimpor kelas memainkannya. Setelah impor lain:
1 |
|
2 |
import com.tutsplus.coverflow.CoverFlow; |
Sekarang kita perlu tempat untuk menyimpan contoh memainkannya. Sebelum pembuat:
1 |
|
2 |
private var coverFlow:CoverFlow; |
Dan sekarang untuk membuat contoh dan menambahkannya ke daftar tampilan. Dalam konstruktor, menghapus jejak dan menggantinya dengan:
1 |
|
2 |
coverFlow = new CoverFlow(); |
3 |
addChild(coverFlow); |
Tes aplikasi Anda sekarang, dan sekarang Anda akan melihat "Memainkannya" jejak di Output panel. Jika demikian, semua baik. Kita sekarang dapat mulai membangun memainkannya.
Berikut adalah kode kelas seluruh dokumen, untuk referensi:
1 |
|
2 |
package { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.events.*; |
6 |
import flash.net.*; |
7 |
import flash.utils.*; |
8 |
|
9 |
import com.tutsplus.coverflow.CoverFlow; |
10 |
|
11 |
public class CoverFlowTest extends Sprite { |
12 |
|
13 |
private var coverFlow:CoverFlow; |
14 |
|
15 |
public function CoverFlowTest() { |
16 |
coverFlow = new CoverFlow(); |
17 |
addChild(coverFlow); |
18 |
}
|
19 |
|
20 |
}
|
21 |
|
22 |
}
|
Step 6: Membuat kelas Cover
Kelas penutup akan item tunggal di seluruh "arus." Kita akan mulai dengan menyempurnakan kelas pada satu item, kemudian khawatir tentang loading data dan membangun "arus" setelah yang dirawat.
Sekali lagi, dalam editor teks Anda, membuat file kelas baru. Simpan sebagai Cover.as dalam folder com/tutsplus/memainkannya yang sama sebagai kelas memainkannya (dibandingkan dengan CoverFlowTest class...yes, kami memiliki beberapa nama yang berpotensi membingungkan. Saya akan mencoba untuk membantu Anda menjaga hal-hal lurus selama tutorial ini).



Tambahkan boilerplate berikut (Lihat pola belum?):
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.utils.*; |
9 |
|
10 |
public class Cover extends Sprite { |
11 |
|
12 |
public function Cover() { |
13 |
trace("Cover"); |
14 |
}
|
15 |
|
16 |
}
|
17 |
|
18 |
}
|
Ini benar-benar identik boilerplate memainkannya, kecuali untuk penggunaan kata "Penutup" bukan "Memainkannya." Ini akan berakhir dengan sangat berbeda, jangan khawatir, aku hanya membuat yakin kita mendapatkan file di tempat sebelum pergi terlalu jauh ke lubang kelinci pengkodean.
Langkah 7: Membuat contoh Cover
Jadi, kita akan memiliki objek memainkannya membuat dan menggunakan sebuah objek penutup. Pada akhirnya, memainkannya akan bertanggung jawab untuk menciptakan dan mengelola beberapa objek Cover, tetapi untuk sekarang, karena kami membangun kelas Cover, kita hanya bisa membuat dan menampilkan objek penutup tunggal.
Dalam memainkannya, bukan menelusuri "Memainkannya," Mari kita memiliki itu melakukan pembuatan obyek ini.
1 |
|
2 |
public function CoverFlow() { |
3 |
var test:Cover = new Cover(); |
4 |
addChild(test); |
5 |
}
|
Jika Anda menguji sekarang, Anda akan melihat "Menutupi" sedang dilacak (ingat, itu adalah penutup satu objek, tidak jejak tes sebelumnya kami telah menggunakan).



Namun, mari kita pergi satu langkah lebih lanjut dan mencoba untuk menampilkan sesuatu pada layar. Di sampul file, menghapus jejak dan menambahkan ini:
1 |
|
2 |
public function Cover() { |
3 |
graphics.beginFill(0xff0000); |
4 |
graphics.drawRect(0, 0, 200, 200); |
5 |
}
|
Sekarang, bukan merunut ke Output panel, Anda akan melihat kotak merah muncul di sudut kiri atas dari film Anda. Jika itu terjadi, kita tidak cukup banyak set untuk terus bekerja. Apa ini berarti adalah bahwa tidak hanya kode mengeksekusi semua jalan ke objek penutup individu, tetapi kita telah berhasil menambahkan elemen ke tahap sehingga kita dapat membuat objek visual.



Langkah 8: Menempatkan meliputi dalam wadah
Kami hanya menambahkan objek penutup langsung ke memainkannya tampilan daftar. Untuk alasan yang mungkin tidak jelas pada saat ini, kita akan akhirnya membutuhkannya dalam wadah tambahan; itu adalah, memainkannya akan berisi sebuah Sprite, yang akan berisi semua contoh Cover. Seperti yang kita maju melalui tutorial ini, kita akan menambahkan tampilan lainnya, bebas-Cover objek, dan itu akan sangat nyaman untuk memastikan semua mencakup mudah dikelola.
Pertama, dalam memainkannya, menyatakan properti Sprite yang akan referensi kami kontainer.
1 |
|
2 |
private var _coversContainer:Sprite; |
Dan dalam konstruktor, menciptakan Sprite itu dan menambahkannya ke daftar tampilan. Juga, bukan menambahkan tes penutup objek untuk memainkannya di tampilan daftar, tambahkan ke _coversContainer Sprite:
1 |
|
2 |
public function CoverFlow() { |
3 |
_coversContainer = new Sprite(); |
4 |
addChild(_coversContainer); |
5 |
var test:Cover = new Cover(); |
6 |
_coversContainer.addChild(test); |
7 |
}
|
Jika Anda menguji sekarang, Anda harus melihat hal yang sama seperti sebelumnya, yang baik. Kami tidak ingin terlihat berbeda, tapi kami ingin fungsi yang berbeda di bawah tenda.
Langkah 9: Mengatur ukuran memainkannya
Ada beberapa hal yang kita harus berhati-hati sekarang. Ukuran wadah yang memegang tampilan memainkannya adalah salah satu dari mereka, sebagai lebar dan tinggi akan digunakan di tempat lain. Ini akan menjadi sederhana seperti beberapa properti dan pencocokan setter dan pengambil.
Pertama, dalam CoverFlow.as, tambahkan dua sifat pada awal kelas:
1 |
|
2 |
private var _width:Number; |
3 |
private var _height:Number; |
Dan setelah konstruktor, tambahkan setter dan pengambil berikut:
1 |
|
2 |
override public function set width(num:Number):void { |
3 |
_width = num; |
4 |
}
|
5 |
override public function get width():Number { |
6 |
return _width; |
7 |
}
|
8 |
override public function set height(num:Number):void { |
9 |
_height = num; |
10 |
}
|
11 |
override public function get height():Number { |
12 |
return _height; |
13 |
}
|
Karena memainkannya subclass dari Sprite, sudah ada lebar dan tinggi setter dan pengambil. Jadi kita perlu untuk memastikan untuk menimpa mereka. Kami tidak ingin perilaku default peregangan, jadi kita akan ingin mengontrol yang kita sendiri. Kita akan kembali ke ini setter dalam beberapa langkah.
Namun, memiliki ukuran untuk memainkannya objek cukup penting untuk meminta parameter ini dalam konstruktor. Lebar dan tinggi menentukan banyak tata letak akhir, sehingga kami akan menambahkan beberapa parameter ke konstruktor dan kemudian segera mengatur properti kami dengan mereka:
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
|
6 |
_coversContainer = new Sprite(); |
7 |
addChild(_coversContainer); |
8 |
var test:Cover = new Cover(); |
9 |
_coversContainer.addChild(test); |
10 |
}
|
Dan tentu saja kita perlu menyediakan beberapa argumen ini dari CoverFlowTest. Dalam file tersebut, memperbarui baris yang menciptakan memainkannya baru ini:
1 |
|
2 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
Tidak ada banyak untuk menguji sekarang, tetapi jika Anda suka Anda dapat mempublikasikan film dan melihat jika kesalahan kompilator muncul. Jika ada kesalahan, mengurus mereka sekarang. Anda akan tahu bahwa kesalahan yang entah bagaimana berhubungan dengan kode Anda sehingga hanya mengetik, mulai dari sana.
Langkah 10: Mengatur warna latar belakang
Properti lain yang akan digunakan kemudian akan warna latar belakang dari seluruh "arus." Apple membuat mereka hitam, tapi tidak ada alasan untuk tetap dengan itu, karena akan menjadi agak sederhana untuk mengubahnya. Untuk membuatnya terjadi, meskipun, kita akan membutuhkan sebuah objek bentuk yang duduk di bagian bawah tumpukan tampilan objek memainkannya, dan kita harus pemrograman menggambar persegi panjang dengan warna pilihan ke dalam bentuk itu.
Pertama, tambahkan dua sifat untuk memainkannya, satu untuk memegang contoh bentuk dan satu untuk menyimpan warna latar belakang:
1 |
|
2 |
private var _backgroundColor:uint = 0; |
3 |
private var _background:Shape; |
Perhatikan bahwa kami memberikan _backgroundColor nilai default, sehingga jika pernah diatur oleh pengguna kelas ini, kita akan memiliki latar belakang hitam tetap. Jumlah 0 adalah kode warna untuk hitam.
Selanjutnya, menulis dalam penyetel dan pengambil untuk backgroundColor (kita tidak perlu bentuk agar dapat diakses di luar kelas ini, hanya warna):
1 |
|
2 |
public function set backgroundColor(val:uint):void { |
3 |
_backgroundColor = val; |
4 |
drawBackground(); |
5 |
}
|
6 |
public function get backgroundColor():uint { |
7 |
return _backgroundColor; |
8 |
}
|
Anda akan melihat bahwa kita menyebut sebagai--namun tidak ada metode disebut drawBackground. Ini akan melakukan apa yang ia mengatakan pada label. Mari kita menulis sekarang:
1 |
|
2 |
private function drawBackground():void { |
3 |
_background.graphics.clear(); |
4 |
_background.graphics.beginFill(_backgroundColor, 1); |
5 |
_background.graphics.drawRect(0, 0, _width, _height); |
6 |
}
|
Ini hanya membersihkan keluar setiap grafis sebelumnya dalam bentuk latar belakang, set mengisi warna pada saat ini nilai properti, dan kemudian menarik sebuah persegi panjang.
Akhirnya, kita perlu untuk mengatur bentuk awalnya. Dalam konstruktor, menambahkan ini pada akhir:
1 |
|
2 |
_background = new Shape(); |
3 |
addChildAt(_background, 0); |
4 |
drawBackground(); |
Dan pergi ke depan dan mengujinya! Anda harus melihat latar belakang hitam di belakang kami red square.



Jika Anda suka, Anda dapat mengubah ukuran jendela pemain, dan Anda akan melihat bahwa kita memang memiliki sebuah persegi panjang hitam yang duduk di atas dasar putih film.
Untuk referensi, di sini adalah kelas memainkannya lengkap saat ini. Perubahan yang dibuat dalam langkah ini yang disorot.
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.text.*; |
9 |
import flash.utils.*; |
10 |
|
11 |
public class CoverFlow extends Sprite { |
12 |
|
13 |
private var _coversContainer:Sprite; |
14 |
private var _width:Number; |
15 |
private var _height:Number; |
16 |
private var _backgroundColor:uint = 0; |
17 |
private var _background:Shape; |
18 |
|
19 |
public function CoverFlow(w:Number, h:Number) { |
20 |
_width = w; |
21 |
_height = h; |
22 |
|
23 |
_coversContainer = new Sprite(); |
24 |
addChild(_coversContainer); |
25 |
var test:Cover = new Cover(); |
26 |
_coversContainer.addChild(test); |
27 |
|
28 |
_background = new Shape(); |
29 |
addChildAt(_background, 0); |
30 |
drawBackground(); |
31 |
}
|
32 |
|
33 |
override public function set width(num:Number):void { |
34 |
_width = num; |
35 |
}
|
36 |
override public function get width():Number { |
37 |
return _width; |
38 |
}
|
39 |
override public function set height(num:Number):void { |
40 |
_height = num; |
41 |
}
|
42 |
override public function get height():Number { |
43 |
return _height; |
44 |
}
|
45 |
|
46 |
public function set backgroundColor(val:uint):void { |
47 |
_backgroundColor = val; |
48 |
drawBackground(); |
49 |
}
|
50 |
public function get backgroundColor():uint { |
51 |
return _backgroundColor; |
52 |
}
|
53 |
|
54 |
private function drawBackground():void { |
55 |
_background.graphics.clear(); |
56 |
_background.graphics.beginFill(_backgroundColor, 1); |
57 |
_background.graphics.drawRect(0, 0, _width, _height); |
58 |
}
|
59 |
|
60 |
}
|
61 |
|
62 |
}
|
Langkah 11: Membuat masker
Kami telah menciptakan bentuk latar belakang yang merespon ukuran memainkannya, tapi apa pun kita menambahkan ke objek – seperti individu mencakup-mungkin tidak menghormati ukuran dimaksudkan. Apa yang kita butuhkan adalah masker untuk memainkannya seluruh tampilan objek yang akan ditetapkan untuk ukuran yang sama.
Kita bisa menggunakan masker ol ' biasa untuk tugas ini, tapi karena kami berharap masker persegi panjang, kita memiliki pendekatan yang lebih mudah. Properti scrollRect DisplayObjects menyediakan fungsionalitas mirip dengan masker, meskipun ada perbedaan. Salah satu keuntungan kita memiliki dengan scrollRect adalah optimasi kinerja. Aku tidak tahu secara spesifik, tetapi memanfaatkan scrollRect memberitahu Flash untuk membuat hanya piksel yang terkandung dalam persegi panjang, bukan biasa masker, yang masih menjadikan semua piksel terlibat dalam konten bertopeng.
Pengaturannya yang sederhana seperti ini, dalam konstruktor memainkannya:
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
// ...
|
4 |
|
5 |
drawBackground(); |
6 |
|
7 |
scrollRect = new Rectangle(0, 0, _width, _height); |
8 |
|
9 |
// ...
|
Tidak ada banyak untuk menguji sekarang, tapi Anda dapat mengkompilasi untuk memastikan Anda tidak membuat kesalahan ketik.
Langkah 12: Menyesuaikan lebar dan tinggi
Sekarang, kita perlu untuk mengimplementasikan logika ukuran kita sendiri. Dalam lebar dan tinggi setter memainkannya, tambahkan baris-baris berikut:
1 |
|
2 |
override public function set width(num:Number):void { |
3 |
_width = num; |
4 |
_background.width = _width; |
5 |
scrollRect = new Rectangle(0, 0, _width, _height); |
6 |
}
|
7 |
override public function get width():Number { |
8 |
return _width; |
9 |
}
|
10 |
override public function set height(num:Number):void { |
11 |
_height = num; |
12 |
_background.height = _height; |
13 |
scrollRect = new Rectangle(0, 0, _width, _height); |
14 |
}
|
15 |
override public function get height():Number { |
16 |
return _height; |
17 |
}
|
Kita dapat menguji ini untuk gelar dengan menambahkan perubahan ukuran obyek memainkannya di CoverFlowTest:
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.width = stage.stageWidth / 2; |
6 |
coverFlow.height = stage.stageHeight / 3; |
7 |
}
|
Anda harus melihat apakah Anda telah melihat, hanya bertopeng.



Sulit untuk mengatakan bahwa scrollRect bekerja pada saat ini, tapi setidaknya Anda harapkan hasil untuk sekarang. Menghapus dua baris baru saja ditambahkan; kita akan ingin memainkannya ukuran penuh untuk meneruskan pembangunan.
Langkah 13: Menambahkan properti untuk menutupi
Kita akan kembali ke CoverFlow.as di masa depan, tetapi untuk sekarang kita akan fokus pada mendapatkan instance penutup individu untuk mempercepat.
Mari kita berpikir tentang apa sampul akan perlu untuk melakukan. Ini akan perlu untuk memuat dan menampilkan gambar. Ini akan perlu untuk menampilkan keterangan. Itu harus diposisikan. Ini juga akan perlu untuk menampilkan refleksi di bawah gambar. Ketika kita mendapatkan untuk XML data, kita akan memiliki masing-masing menutupi menyimpan node XML yang berkaitan dengan hal itu, sehingga kita dapat menyimpan informasi tambahan terkait dengan penutup terkait. Dan akan perlu untuk mengirimkan beberapa peristiwa, kemajuan beban, beban lengkap, pilih (untuk ketika penutup datang ke posisi tengah), dan klik. Sampul pasti bisa berbuat lebih banyak, tetapi untuk sekarang, kemampuan ini sangat erat cocok apa iTunes pelaksanaan Cover Flow tidak, dan akan membantu menjaga kami tutorial untuk lingkup yang wajar. Untuk kode, set fitur ini berarti:
Memuat gambar yang kita akan membutuhkan sebuah Loader untuk memuat gambar, bersama dengan menentukan URL gambar untuk memuat.
Menampilkan gambar yang kita harus menambahkan Loader ke tampilan daftar.
Tampilan Caption kita akan perlu untuk dapat mengatur keterangan, memasukkannya ke dalam TextField, dan menampilkan TextField. Catatan bahwa ini membuka kaleng cacing yang gaya teks, dan pertanyaan tentang berapa banyak kontrol gaya untuk membuka di luar kelas. Untuk tujuan kita, kita akan tetap dengan style standar. Jika Anda ingin sebuah implementasi yang memungkinkan user-ditentukan gaya, itu adalah latihan untuk nanti.
Namun, perhatikan bahwa dalam referensi pelaksanaan Cover Flow, keterangan tidak terikat pada gambar cover, ini adalah daerah yang tetap di bawah pusat di seluruh tampilan layar. Apa yang akan kita butuhkan adalah tidak TextField untuk setiap objek Cover, tetapi TextField tunggal untuk seluruh sistem memainkannya. Semua penutup objek perlu lakukan adalah menyimpan keterangannya. Kita akan memiliki memainkannya kemudian menarik informasi dari masing-masing menutupi seperti yang terfokus dan menangani dengan tampilan. Sehingga semua kita benar-benar butuhkan sekarang adalah sebuah mekanisme penyimpanan untuk keterangan.
Tampilan gambar refleksi ini akan membutuhkan sebuah objek Bitmap dan fanciness BitmapData beberapa, tapi tidak sulit. Namun, itu memerlukan bahwa kita tahu warna latar belakang umum Cover Flow seluruh layar, karena cara termudah untuk menangani transparansi refleksi adalah tidak benar-benar menjadi transparan (jika mereka, kita akan memiliki overlaying refleksi Tampilkan melalui satu sama lain). Jadi, kami akan memerlukan bahwa warna latar belakang dilewatkan dalam ke konstruktor kami dari memainkannya.
Juga, kita akan ingin menggantung ke Bitmap, tetapi BitmapData dapat menjadi suatu obyek yang digunakan untuk membuat refleksi di tempat pertama.
Posisi karena kami sedang subclassing Sprite, apa pun yang kita menampilkan dalam Sprite yang secara otomatis diposisikan sebagai unit oleh sifat posisi sprite. Kita tidak perlu melakukan apa-apa untuk mendapatkan fungsi ini, selain pastikan bahwa kita menambahkan objek tampilan sesuai sebagai anak-anak dari contoh penutup itu sendiri.
XML Data kita akan hanya perlu tempat untuk menyimpan node XML sewenang-wenang dan cara untuk mendapatkan itu kembali keluar dari objek.
Peristiwa lagi, karena kita subclass dari Sprite, kami juga secara otomatis memiliki kemampuan untuk mengirimkan peristiwa. Pada kenyataannya, acara klik sudah didefinisikan oleh Sprite. Beban kemajuan dan lengkap akan benar-benar hanya diteruskan peristiwa dari LoaderInfo Loader yang kita gunakan untuk memuat gambar. Dan pilih akan benar-benar ditangani oleh memainkannya, karena tahu cara untuk mengelola koleksi selimut. Jadi, kita sudah selesai dengan yang satu ini, juga!
Mari kita tambahkan sifat-sifat yang kita butuhkan, setter dan pengambil dimana tepat. Kita akan mengikuti konvensi membuat sebenarnya properti pribadi, dan memberikan akses publik melalui setter dan pengambil.
Dalam Cover.as, menambahkan beberapa properti untuk file kelas. Saya suka untuk menjaga mereka dikelompokkan bersama-sama, di bagian paling atas dari definisi kelas:
1 |
|
2 |
private var _src:String; |
3 |
private var _caption:String; |
4 |
private var _data:XML; |
5 |
private var _loader:Loader; |
6 |
private var _reflection:Bitmap; |
7 |
private var _backgroundColor:uint; |
Menulis dan setter Getter:
1 |
|
2 |
public function get caption():String { |
3 |
return _caption; |
4 |
}
|
5 |
|
6 |
public function get data():XML { |
7 |
return _data; |
8 |
}
|
9 |
|
10 |
public function set backgroundColor(num:Number):void { |
11 |
_backgroundColor = num; |
12 |
}
|
13 |
public function get backgroundColor():Number { |
14 |
return _backgroundColor; |
15 |
}
|
Mengapa hanya memiliki ini? Yah, benda-benda lain benar-benar tidak perlu akses ke Bitmap atau Loader, dan untuk keterangan dan data, kami akan beroperasi pada asumsi bahwa setelah nilai-nilai yang ditetapkan, mereka tidak perlu mengubah. Kita akan berurusan dengan yang di langkah berikutnya.
Pergi ke depan dan menguji hal ini. Tidak akan ada perubahan untuk mencatat; Anda harus masih hanya melihat kotak merah. Tapi dengan menguji film kita menjalankan hal-hal melalui compiler, yang membantu kita menemukan kesalahan harus ada diperkenalkan. Jika semua berjalan lancar, film akan berjalan dan Anda akan melihat red square. Di sini adalah kelas penutup lengkap sampai sekarang:
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.utils.*; |
9 |
|
10 |
public class Cover extends Sprite { |
11 |
|
12 |
private var _src:String; |
13 |
private var _caption:String; |
14 |
private var _data:XML; |
15 |
private var _loader:Loader; |
16 |
private var _reflection:Bitmap; |
17 |
private var _backgroundColor:uint; |
18 |
|
19 |
public function Cover() { |
20 |
graphics.beginFill(0xff0000); |
21 |
graphics.drawRect(0, 0, 200, 200); |
22 |
}
|
23 |
|
24 |
public function get caption():String { |
25 |
return _caption; |
26 |
}
|
27 |
|
28 |
public function get data():XML { |
29 |
return _data; |
30 |
}
|
31 |
|
32 |
public function set backgroundColor(num:Number):void { |
33 |
_backgroundColor = num; |
34 |
}
|
35 |
public function get backgroundColor():Number { |
36 |
return _backgroundColor; |
37 |
}
|
38 |
|
39 |
}
|
40 |
|
41 |
}
|
Langkah 14: Mengatur properti
Seperti disebutkan, kami akan menetapkan sifat seperti teks, data dan warna latar belakang melalui konstruktor. Memodifikasi Pembina Cover.as sehingga dibutuhkan tiga nilai, dan kemudian transfer nilai-nilai tersebut ke sifat yang sesuai. Perubahan ke konstruktor di bawah ini yang disorot:
1 |
|
2 |
public function Cover(caption:String, data:XML, backgroundColor:Number) { |
3 |
_caption = caption; |
4 |
_data = data; |
5 |
_backgroundColor = backgroundColor; |
6 |
|
7 |
graphics.beginFill(0xff0000); |
8 |
graphics.drawRect(0, 0, 200, 200); |
9 |
}
|
Sekarang, kembali di CoverFlow.as, kita perlu memberikan nilai ketika kita membuat tes kami penutup atau lain kita akan mendapatkan kesalahan. Dalam konstruktor:
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
|
6 |
_coversContainer = new Sprite(); |
7 |
addChild(_coversContainer); |
8 |
var test:Cover = new Cover("I am a caption", <data />, _backgroundColor); |
9 |
_coversContainer.addChild(test); |
10 |
|
11 |
_background = new Shape(); |
12 |
addChildAt(_background, 0); |
13 |
drawBackground(); |
14 |
|
15 |
scrollRect = new Rectangle(0, 0, _width, _height); |
16 |
}
|
Kami jelas menggunakan dummy data sekarang, tapi ini aman harus mengkompilasi. Sekali lagi, kita tidak akan melihat perubahan apapun, tetapi tes film untuk memastikan Anda belum memperkenalkan kesalahan. Namun, kita dapat menulis tes cepat dari apa yang kita menulis dengan menelusuri nilai-nilai pengambil. Masih dalam konstruktor memainkannya:
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
|
6 |
_coversContainer = new Sprite(); |
7 |
addChild(_coversContainer); |
8 |
var test:Cover = new Cover("I am a caption", <data />, _backgroundColor); |
9 |
_coversContainer.addChild(test); |
10 |
|
11 |
_background = new Shape(); |
12 |
addChildAt(_background, 0); |
13 |
drawBackground(); |
14 |
|
15 |
scrollRect = new Rectangle(0, 0, _width, _height); |
16 |
|
17 |
trace(test.caption); |
18 |
trace(test.data.toXMLString()); |
19 |
trace(test.backgroundColor); |
20 |
}
|
Anda harus melihat berikut dalam panel Output Anda:



Ini memverifikasi bahwa kita benar pengaturan dan mendapatkan setidaknya caption, data XML dan backgroundColor properti.
Langkah 15: Memuat gambar
Untuk langkah ini, kita akan perlu gambar untuk memuat. Ada beberapa dalam paket download untuk tutorial ini, sudah dipotong dan berukuran sebagai kotak. Mari kita hanya memilih satu untuk memuat. Aku akan menggunakan "best.jpg."
Pertama, meletakkan folder gambar dalam folder proyek yang sama yang Anda telah menggunakan. Seharusnya berada di lokasi yang sama seperti CoverFlowTest.swf Anda. Baik drop folder foto dari download di sini, atau membuat folder foto Anda sendiri di sini dan menempatkan gambar yang Anda inginkan untuk me-load ke dalam folder itu.



Selanjutnya, dalam konstruktor Cover.as, menghapus garis-garis yang menarik red square.
1 |
|
2 |
public function Cover(caption:String, data:XML, backgroundColor:Number) { |
3 |
_caption = caption; |
4 |
_data = data; |
5 |
_backgroundColor = backgroundColor; |
6 |
|
7 |
//graphics.beginFill(0xff0000);
|
8 |
//graphics.drawRect(0, 0, 200, 200);
|
9 |
}
|
Sekarang, membuat metode umum yang disebut beban. Ini akan menerima string URL sebagai parameter, menyimpannya dalam properti _src, dan kemudian load gambar dari URL itu.
1 |
|
2 |
public function load(src:String):void { |
3 |
_src = src; |
4 |
_loader = new Loader(); |
5 |
_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress); |
6 |
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); |
7 |
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError); |
8 |
addChild(_loader); |
9 |
_loader.load(new URLRequest(_src)); |
10 |
}
|
Ini adalah standar Loader hal. Ini akhirnya akan sampai dengan objek lain (seperti memainkannya) untuk memberi makan nilai ini penutup.
Kami telah menambahkan tiga pendengar acara, Semua makanan standar untuk loading. Mari kita menulis beberapa fungsi pendengar rintisan sehingga kita dapat menguji. Tambahkan kode ini ke kelas Anda. Ini adalah metode baru, tidak kode dalam metode lain:
1 |
|
2 |
private function onLoadProgress(e:ProgressEvent):void { |
3 |
trace("progress: " + e.bytesLoaded + " of " + e.bytesTotal); |
4 |
}
|
5 |
|
6 |
private function onLoadComplete(e:Event):void { |
7 |
trace("loaded"); |
8 |
}
|
9 |
|
10 |
private function onLoadError(e:IOErrorEvent):void { |
11 |
trace("error: " + e.text) |
12 |
}
|
Akhirnya kita akan melakukan sesuatu yang lebih berguna dengan ini, tetapi untuk sekarang kita akan api dari jejak hanya untuk memastikan fungsi dipanggil dalam menanggapi peristiwa. Untuk referensi, seluruh kelas harus terlihat seperti ini (tambahan dari langkah ini disorot):
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.utils.*; |
9 |
|
10 |
public class Cover extends Sprite { |
11 |
|
12 |
private var _src:String; |
13 |
private var _caption:String; |
14 |
private var _data:XML; |
15 |
private var _loader:Loader; |
16 |
private var _reflection:Bitmap; |
17 |
private var _backgroundColor:uint; |
18 |
|
19 |
public function Cover(caption:String, data:XML, backgroundColor:Number) { |
20 |
_caption = caption; |
21 |
_data = data; |
22 |
_backgroundColor = backgroundColor; |
23 |
}
|
24 |
|
25 |
public function get caption():String { |
26 |
return _caption; |
27 |
}
|
28 |
|
29 |
public function get data():XML { |
30 |
return _data; |
31 |
}
|
32 |
|
33 |
public function set backgroundColor(num:Number):void { |
34 |
_backgroundColor = num; |
35 |
}
|
36 |
public function get backgroundColor():Number { |
37 |
return _backgroundColor; |
38 |
}
|
39 |
|
40 |
public function load(src:String):void { |
41 |
_src = src; |
42 |
_loader = new Loader(); |
43 |
_loader.contentLoaderInfo.addEventListener(ProgressEvent.PROGRESS, onLoadProgress); |
44 |
_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onLoadComplete); |
45 |
_loader.contentLoaderInfo.addEventListener(IOErrorEvent.IO_ERROR, onLoadError); |
46 |
addChild(_loader); |
47 |
_loader.load(new URLRequest(_src)); |
48 |
}
|
49 |
|
50 |
private function onLoadProgress(e:ProgressEvent):void { |
51 |
trace("progress: " + e.bytesLoaded + " of " + e.bytesTotal); |
52 |
}
|
53 |
|
54 |
private function onLoadComplete(e:Event):void { |
55 |
trace("loaded"); |
56 |
}
|
57 |
|
58 |
private function onLoadError(e:IOErrorEvent):void { |
59 |
trace("error: " + e.text) |
60 |
}
|
61 |
|
62 |
}
|
63 |
|
64 |
}
|
Sekarang, untuk menguji ini, kita perlu untuk naik kembali ke CoverFlow.as dan di beberapa titik dalam konstruktor, memanggil metode beban dan lulus dalam berlaku path ke gambar:
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
|
6 |
_coversContainer = new Sprite(); |
7 |
addChild(_coversContainer); |
8 |
var test:Cover = new Cover("I am a caption", <data />, _backgroundColor); |
9 |
_coversContainer.addChild(test); |
10 |
|
11 |
_background = new Shape(); |
12 |
addChildAt(_background, 0); |
13 |
drawBackground(); |
14 |
|
15 |
scrollRect = new Rectangle(0, 0, _width, _height); |
16 |
|
17 |
trace(test.caption); |
18 |
trace(test.data.toXMLString()); |
19 |
trace(test.backgroundColor); |
20 |
|
21 |
test.load("images/best.jpg"); |
22 |
}
|
Jika Anda menguji film sekarang, tidak hanya harus Anda melihat gambar muncul tempat red square:



... tapi Anda juga harus melihat beberapa jejak di panel Output yang mengkonfirmasikan bahwa kemajuan dan lengkap peristiwa penembakan (kemajuan Anda sebenarnya acara mungkin berbeda):



Jelas, beban selesai karena gambar muncul, tetapi baik untuk memastikan kita terhubung acara dengan benar. Jika Anda ingin menguji acara kesalahan, hanya mengubah nilai jalan melintasi konstruktor penutup untuk sesuatu yang tidak akan bekerja, dan Anda akan melihat jejak berbeda.
Langkah 16: Pusat gambar
Gerakan dalam "arus" memiliki dua persyaratan. Pertama, item perlu memutar tentang sumbu vertikal yang berpusat horizontal pada gambar. Kedua, Bagian bawah gambar perlu disesuaikan dengan "tanah" sehingga gambar dari berbagai tinggi semua "duduk" pada pesawat yang sama.
Untuk memudahkan rotasi vertikal, kita dapat pusat gambar horizontal dalam kaitannya dengan Sprite yang mengandung. Demikian pula, untuk memudahkan penyelarasan bawah, kami dapat posisi gambar sehingga ujung bawah di sumbu x sprite yang mengandung. Untuk menarik ini off, kita perlu tahu ukuran gambar yang kita baru saja dimuat. Untuk menentukan bahwa, kita perlu memastikan bahwa gambar ini dimuat sebelum mencoba untuk bekerja dengan ukuran. Jadi, semua kebutuhan kode kita centering berada di handler lengkap.
Menambahkan ini ke metode onLoadComplete Cover.as (dan menghapus jejak yang ada saat ini):
1 |
|
2 |
private function onLoadComplete(e:Event):void { |
3 |
_loader.x = -Math.round(_loader.width / 2); |
4 |
_loader.y = -_loader.height; |
5 |
}
|
Jika Anda menguji ini sekarang, Anda mungkin tidak akan melihat gambar sama sekali, karena sprite penutup yang diposisikan di (0, 0) di panggung, tapi semua yang terlihat konten adalah di atas titik pendaftaran sprite penutup. Jadi, sebelum pengujian, menambahkan beberapa baris kode untuk posisi objek penutup di CoverFlow.as, hanya setelah membuat tes penutup objek:
1 |
|
2 |
test.x = _width / 2; |
3 |
test.y = _height / 2; |
Tes aplikasi Anda sekarang, dan Anda akan melihat gambar di suatu tempat di tengah panggung.
Jika Anda suka, Anda dapat kembali dan kembali menguji pengaturan lebar dan tinggi memainkannya (Lihat langkah 12) untuk melihat apakah scrollRect bekerja untuk keluar memainkannya isi topeng. Anda akan melihat sebuah objek penutup parsial.
Langkah 17: Mencerminkan Image
Sekarang kita masuk ke dalam beberapa hal yang lebih menantang. Kita akan mengambil gambar yang kita baru saja dimuat dan menciptakan salinan yang membalik vertikal (yaitu adalah berputar di sekitar tepi bagian bawah). Kita akan menggunakan BitmapData untuk mengkloning tampilan gambar. Seperti sebelumnya, karena kita perlu gambar yang sebenarnya sebelum kita bisa melakukan ini, kita akan memulai gambar refleksi dalam onLoadComplete metode:
1 |
|
2 |
private function onLoadComplete(e:Event):void { |
3 |
_loader.x = -Math.round(_loader.width / 2); |
4 |
_loader.y = -_loader.height; |
5 |
drawReflection(); |
6 |
}
|
7 |
|
8 |
private function drawReflection():void { |
9 |
var clone:BitmapData = new BitmapData(_loader.width, _loader.height, false, 0x000000); |
10 |
var flip:Matrix = new Matrix(); |
11 |
flip.scale(1, -1); |
12 |
flip.translate(0, _loader.height); |
13 |
clone.draw(_loader, flip); |
14 |
_reflection = new Bitmap(clone); |
15 |
addChild(_reflection); |
16 |
_reflection.x = _loader.x; |
17 |
}
|
Itulah banyak kode yang mungkin asing bagi Anda, tergantung pada berapa banyak Anda telah bekerja dengan BitmapData.
BitmapData, pertama-tama, adalah kelas yang memungkinkan Anda bekerja dengan pixel bitmap. Baris pertama menciptakan satu, menentukan lebar dan tinggi, transparansi, dan default mengisi warna.
Hal berikutnya yang akan kita lakukan adalah biasanya operasi lurus ke depan, mana kita menarik grafis lain tampilan objek menjadi representasi diberikan bitmap. Namun, kita tidak ingin sebuah klon lurus, kami ingin membalik gambar. Kita bisa melakukannya oleh lewat di sebuah matriks objek ke parameter kedua metode menarik. Sebuah objek matriks mewakili geometris, dua dimensi transformasi, termasuk skala, rotasi, dan terjemahan (atau posisi). Jadi, sebelum kita melakukan operasi menarik, kami membuat objek matriks baru. Kemudian kita akan menggunakan metoda skala pada matriks untuk flip vertikal (dua argumen adalah skala horisontal dan vertikal skala; 1 menjadi tidak ada perubahan dan menjadi inversi -1). Selanjutnya, karena skala operasi melakukan demikian pula untuk bagaimana menampilkan benda bekerja, kita benar-benar skala gambar sehingga "menunjuk" arah lain. Jadi kita perlu reposisi untuk mendapatkan kembali ke kanvas bitmap. Metode terjemahan melakukan ini, reposisi skala gambar menurut gambar tinggi.
Dengan membalik gambar diwakili dalam sebuah objek BitmapData, kita perlu untuk benar-benar menampilkannya dalam sebuah Bitmap objek. BitmapData adalah representasi data yang murni dan tidak, itu sendiri, tampilan. Namun, objek Bitmap dapat, dan mudah cukup mengambil BitmapData objek sebagai parameter ke konstruktor nya, jadi kita membuat Bitmap, menambahkannya ke daftar tampilan dan akhirnya posisi itu horizontal untuk itu selaras dengan gambar asli.
Coba ini keluar, dan Anda harus melihat ganda.



Operasi BitmapData yang dapat membingungkan, jadi jika mereka tidak jelas bagi Anda saat ini saya mendorong Anda untuk melanjutkan informasi di atasnya. BitmapData membuka beberapa kemungkinan yang sangat menarik, jadi it's worth belajar lebih banyak tentang.
Langkah 18: Memudar refleksi
Sekarang, untuk membuat refleksi memudar, kita perlu memudar untuk warna latar belakang, dan menjaga refleksi buram. Ini akan memberikan tampilan yang transparan, tapi jika kita menjaga buram, satu refleksi dapat berlapis di atas lain tanpa semakin rendah satu menampilkan melalui. Pergi ke depan dan melihat preview lagi jika Anda perlu untuk memvisualisasikan ini:



Kami akan menambahkan sekelompok gambar kode untuk drawReflection (di Cover.as). Berikut adalah seluruh metode, dengan perubahan disorot:
1 |
|
2 |
private function drawReflection():void { |
3 |
var clone:BitmapData = new BitmapData(_loader.width, _loader.height, false, 0x000000); |
4 |
var flip:Matrix = new Matrix(); |
5 |
flip.scale(1, -1); |
6 |
flip.translate(0, _loader.height); |
7 |
clone.draw(_loader, flip); |
8 |
_reflection = new Bitmap(clone); |
9 |
addChild(_reflection); |
10 |
_reflection.x = _loader.x; |
11 |
|
12 |
var gradient:Shape = new Shape(); |
13 |
var gradientMatrix:Matrix = new Matrix(); |
14 |
gradientMatrix.createGradientBox(_reflection.width, _reflection.height, Math.PI / 2); |
15 |
var gradientFill:GraphicsGradientFill = new GraphicsGradientFill(GradientType.LINEAR, [_backgroundColor, _backgroundColor], [.5, 1], [0, 255], gradientMatrix); |
16 |
var gradientRect:GraphicsPath = new GraphicsPath(); |
17 |
gradientRect.moveTo(0, 0); |
18 |
gradientRect.lineTo(_reflection.width, 0); |
19 |
gradientRect.lineTo(_reflection.width, _reflection.height); |
20 |
gradientRect.lineTo(0, _reflection.height); |
21 |
gradientRect.lineTo(0, 0); |
22 |
var graphicsData:Vector.<IGraphicsData> = new Vector.<IGraphicsData>(); |
23 |
graphicsData.push(gradientFill, gradientRect); |
24 |
gradient.graphics.drawGraphicsData(graphicsData); |
25 |
|
26 |
_reflection.bitmapData.draw(gradient); |
27 |
}
|
Yup, itu adalah cukup banyak kode untuk mengunyah. Singkatnya, itu menciptakan objek bentuk lain, di mana kita menarik gradien linier. Gradien diatur menjadi warna yang sama sebagai latar belakang utama, dengan alpha perubahan yang terjadi dari setengah transparan untuk sepenuhnya buram, atas ke bawah. Gradien ini kemudian mendapat digabung menjadi BitmapData yang sudah berisi refleksi membalik gambar, sehingga efek akhir adalah refleksi yang memudar keluar untuk warna latar belakang.
Pergi ke depan dan coba ini keluar, Anda harus merasa baik tentang mendapatkan hasil ini:



Namun, jika Anda menguji ini lebih lanjut dan mencoba mendirikan contoh memainkannya di CoverFlowTest dengan warna latar belakang selain hitam, Anda akan melihat beberapa hasil yang tak terduga:



Kami akan alamat berikutnya ini.
Langkah 19: menjaga melacak yang contoh Cover
Kami saat ini menggunakan contoh memainkannya sebagai tempat untuk menguji satu contoh Cover. Dan meskipun kami akan akhirnya menyingkirkan contoh tes, kita sekarang perlu untuk menyimpannya di daftar resmi dari semua kasus. Kita akan menciptakan Array menutupi kasus, dan setiap orang yang mendapat menciptakan akan disimpan dalam Array. Sebenarnya, karena kami menargetkan Flash 10, kita dapat membuat vektor, yang akan menawarkan peningkatan kinerja kecil.
Pertama, di CoverFlow.as, menyatakan vektor, bersama dengan sisa properti:
1 |
|
2 |
private var _covers:Vector.<Cover>; |
Kemudian, instantiate vektor yang segera. Dalam konstruktor, meletakkan baris ini tepat setelah Anda mengatur _width dan _height:
1 |
|
2 |
_covers = new Vector.<Cover>(); |
Dan setelah "ujian" menutupi objek telah dibuat (masih dalam konstruktor), menambahkannya ke vektor:
1 |
|
2 |
_covers.push(test); |
Bagian atas kelas memainkannya Anda akan terlihat seperti ini (tambahan disorot):
1 |
|
2 |
public class CoverFlow extends Sprite { |
3 |
|
4 |
private var _coversContainer:Sprite; |
5 |
private var _width:Number; |
6 |
private var _height:Number; |
7 |
private var _backgroundColor:uint = 0; |
8 |
private var _background:Shape; |
9 |
private var _covers:Vector.<Cover>; |
10 |
|
11 |
public function CoverFlow(w:Number, h:Number) { |
12 |
_width = w; |
13 |
_height = h; |
14 |
_covers = new Vector.<Cover>(); |
15 |
|
16 |
_coversContainer = new Sprite(); |
17 |
addChild(_coversContainer); |
18 |
var test:Cover = new Cover("I am a caption", <data />, _backgroundColor); |
19 |
_coversContainer.addChild(test); |
20 |
test.x = _width / 2; |
21 |
test.y = _height / 2; |
22 |
_covers.push(test); |
23 |
|
24 |
trace(test.caption); |
25 |
trace(test.data.toXMLString()); |
26 |
trace(test.backgroundColor); |
27 |
|
28 |
test.load("images/best.jpg"); |
29 |
|
30 |
_background = new Shape(); |
31 |
addChildAt(_background, 0); |
32 |
drawBackground(); |
33 |
}
|
34 |
// ...
|
Langkah 20: Mengatur warna latar belakang dari selimut
Sekarang, di backgroundColor setter, kita tidak hanya perlu untuk menarik latar belakang utama, tetapi kita perlu menginformasikan semua kasus penutup kami yang telah berubah warna latar belakang. Seluruh metode akan terlihat seperti ini (kode disorot):
1 |
|
2 |
public function set backgroundColor(val:uint):void { |
3 |
_backgroundColor = val; |
4 |
drawBackground(); |
5 |
for each (var cover:Cover in _covers) { |
6 |
cover.backgroundColor = val; |
7 |
}
|
8 |
}
|
Kemudian, di kelas Cover, memperbarui setter backgroundColor nya sehingga itu redraws refleksi:
1 |
|
2 |
public function set backgroundColor(num:Number):void { |
3 |
_backgroundColor = num; |
4 |
drawReflection(); |
5 |
}
|
Terakhir, kita perlu untuk melakukan pengecekan kesalahan. Dalam kasus uji bahwa kami telah menyiapkan sekarang, backgroundColor mendapat ditetapkan sebelum gambar beban (dan ini adalah tindakan yang wajar; biasanya Anda akan mengatur memainkannya dan memberikannya backgroundColor segera, seperti yang memuat gambar). Karena ini, Loader memiliki lebar dan tinggi dari 0, yang membuat baris pertama dari drawReflection menghasilkan kesalahan. Jika Anda menetapkan backgroundColor objek memainkannya sekarang dan menguji film, Anda akan melihat ini:



Hal ini cukup mudah untuk menangani. Jika Loader memiliki lebar dan/atau ketinggian 0, kita bisa berasumsi bahwa loader belum selesai loading belum. Jadi, baris pertama drawReflection dapat memeriksa ini:
1 |
|
2 |
private function drawReflection():void { |
3 |
if (_loader.width == 0 || _loader.height == 0) { |
4 |
return; |
5 |
}
|
6 |
var clone:BitmapData = new BitmapData(_loader.width, _loader.height, false, 0x000000); |
7 |
var flip:Matrix = new Matrix(); |
8 |
// ...
|
Hanya keluar metode, dan semuanya akan beres. Jangan khawatir, kita juga menyebut drawReflection dari onLoadComplete, jadi saat itu, properti _backgroundColor akan ditetapkan dengan nilai yang benar, dan Loader akan dimuat, sehingga kita dapat menarik. Dalam hal kita ingin mengubah warna latar belakang setelah gambar telah dimuat, ini masih bekerja, karena Loader akan memiliki dimensi bukan nol, dan drawReflection akan berjalan dari backgroundColor setter.
Mencobanya: kembali ke CoverFlowTest dan mengatur contoh memainkannya latar belakang warna:
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.backgroundColor = 0xC14216; |
6 |
}
|
Dan Anda akan memiliki satu jeruk mulia yang terjadi:



Merasa bebas untuk menghapus baris setelah Anda puas bahwa warna latar belakang dan refleksi bekerja (apa, Anda tidak suka orange?).
Langkah 21: Menulis sumber Data XML
Kita akan melanjutkan untuk menyediakan satu set data yang nyata untuk mendorong sepotong ini. Citra tes kita bisa pergi, dan kita akan mulai menampilkan satu set gambar.
Kami akan beranggapan bahwa untuk menyediakan data untuk objek memainkannya, itu akan paling mungkin disediakan sebagai file XML eksternal. Ini membuat lebih mudah perubahan hidup konten, tetapi juga memungkinkan kita untuk memuat lebih dari satu file XML untuk menggunakan kembali memainkannya modul yang sama dengan konten yang berbeda dalam film sama.
Sebelum kita menulis ActionScript untuk menangani XML, mari kita menulis file XML kami. Buat sebuah file teks baru yang disebut coverFlowImages.xml dalam folder yang sama sebagai CoverFlow.fla file. Akan ada akar, tentu saja, dan dalam itu hanya akan menjadi daftar gambar node, satu untuk setiap item untuk muncul di aliran. Format umum untuk node gambar akan terlihat seperti ini:
1 |
|
2 |
<image src="path/to/image.jpg" title="A Titillating Title"> |
3 |
whatever data we want to associate with the image |
4 |
</image>
|
Hal ini diasumsikan bahwa gambar akan memiliki jalur gambar, dan mungkin judul. Namun, kita mungkin ingin mengaitkan data lebih dengan setiap gambar, yang mungkin saja teks sederhana, atau kami bahkan dapat menyediakan struktur XML bersarang dengan data yang kompleks dalam, misalnya:
1 |
|
2 |
<image src="people/DruKepple.jpg" title="Dru Kepple, ActionScript Implementor"> |
3 |
<name>
|
4 |
<first>Dru</first> |
5 |
<last>Kepple</last> |
6 |
</name>
|
7 |
<employment>
|
8 |
<company name="Summit Projects" url="https://www.summitprojects.com" /> |
9 |
<company name="Art Institute of Portland" url="http://www.aidepartments.com" /> |
10 |
</employment>
|
11 |
<websites>
|
12 |
<site url="summitprojectsflashblog.wordpress.com" /> |
13 |
<site url="www.thekeppleeffect.com" /> |
14 |
<site url="active.tutsplus.com/author/dru-kepple" /> |
15 |
<site url="www.linkedin.com/drukepple" /> |
16 |
</websites>
|
17 |
</image>
|
Intinya di sini adalah bahwa dalam gambar node, kita dapat menempatkan apapun yang kita inginkan (dari panjang dan kompleks XML data tidak sama sekali). Data ini akan tersedia melalui kelas memainkannya, sebagai node XML itu.
Berikut adalah dokumen lengkap kami akhir (saya menggunakan gambar dan link lain dalam membangun), daftar gambar dan data yang diambil dari active.tutsplus.com:
1 |
|
2 |
<coverflow>
|
3 |
<image src="images/megaphone.jpg" title="HTML5, Flash and RIAs: 18 Industry Experts Have Their Say"> |
4 |
<link>http://active.tutsplus.com/articles/roundups/html5-and-flash-17-industry-experts-have-their-say/</link> |
5 |
</image>
|
6 |
<image src="images/magnifyer.jpg" title="Create an Impressive Magnifying Effect with ActionScript 3.0"> |
7 |
<link>http://active.tutsplus.com/tutorials/effects/create-an-impressive-magnifying-effect-with-actionscript-30/</link> |
8 |
</image>
|
9 |
<image src="images/as3101.jpg" title="AS3 101: Five Reasons to use Setters and Getters"> |
10 |
<link>http://active.tutsplus.com/tutorials/actionscript/as3-101-five-reasons-to-use-setters-and-getters/</link> |
11 |
</image>
|
12 |
<image src="images/montypython.jpg" title="10 Flash Things You Can’t Do With HTML5"> |
13 |
<link>http://active.tutsplus.com/articles/roundups/10-flash-things-you-can’t-do-with-html5/</link> |
14 |
</image>
|
15 |
<image src="images/bad.jpg" title="Blog Action Day: Clean up With a Beautiful Watery Game"> |
16 |
<link>http://active.tutsplus.com/tutorials/games/blog-action-day-clean-up-with-a-beautiful-watery-game/</link> |
17 |
</image>
|
18 |
<image src="images/hype.jpg" title="Create a Mesmeric Music Visualizer with HYPE"> |
19 |
<link>http://active.tutsplus.com/tutorials/effects/create-a-mesmeric-music-visualizer-with-hype/</link> |
20 |
</image>
|
21 |
<image src="images/max.jpg" title="Smart AS3 Video Loading with GreenSock LoaderMax – Free Active Premium!"> |
22 |
<link>http://active.tutsplus.com/tutorials/actionscript/smart-as3-video-loading-with-greensock-loadermax-free-active-premium/</link> |
23 |
</image>
|
24 |
<image src="images/50twitterers.jpg" title="50 More Flash Twitterers Worth Following"> |
25 |
<link>http://active.tutsplus.com/articles/roundups/50-more-flash-twitterers-worth-following/</link> |
26 |
</image>
|
27 |
<image src="images/open_mic_prefixes.jpg" title="Open Mike: Prefixes"> |
28 |
<link>http://active.tutsplus.com/articles/open-mike/open-mike-prefixes/</link> |
29 |
</image>
|
30 |
<image src="images/fullscreen_website.jpg" title="Create a Full Screen, Scalable Flash Website: Part 1"> |
31 |
<link>http://active.tutsplus.com/tutorials/web-design/create-a-full-screen-scalable-flash-website-part-1/</link> |
32 |
</image>
|
33 |
</coverflow>
|
Tampak seperti banyak, tetapi itu adalah benar-benar hanya daftar gambar node dengan dua atribut, src dan judul, dan <link> node bersarang dalam<image>node, yang memiliki URL artikel yang terkait dengan gambar.</image>
Langkah 22: Memuat XML File
Untuk memuat XML, kita akan perlu tempat untuk menyimpan XML, dan properti URLLoader untuk memuat XML. Kami akan memerlukan metode umum untuk memulai beban dengan String URL, beberapa internal event handler untuk URLLoader untuk menangani peristiwa-peristiwa beban XML. Unsur-unsur dari langkah ini cukup standar tarif untuk memuat XML, jadi saya hanya akan tumpukan itu semua dalam satu langkah dan tidak menghabiskan terlalu banyak waktu menjelaskan hal-hal.
Mulailah dengan menambahkan dua sifat, satu untuk urlLoader dan satu untuk xml, di bagian atas kelas memainkannya, dengan sisa properti.
1 |
|
2 |
private var _urlLoader:URLLoader; |
3 |
private var _xml:XML; |
Dalam konstruktor memainkannya 's, membuat dan mengatur URLLoader (tidak benar-benar peduli mana dalam konstruktor, tapi aku 'm memilih pada akhir):
1 |
|
2 |
_urlLoader = new URLLoader(); |
3 |
_urlLoader.addEventListener(Event.COMPLETE, onXMLLoad); |
4 |
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onXMLLoadError); |
Menulis acara URLLoader fungsi penanganan, di suatu tempat di tubuh utama dari kelas Anda:
1 |
|
2 |
private function onXMLLoad(e:Event):void { |
3 |
_xml = new XML(_urlLoader.data); |
4 |
trace("XML Loaded:\n" + _xml); |
5 |
}
|
6 |
|
7 |
private function onXMLLoadError(e:IOErrorEvent):void { |
8 |
trace("There was an error loading the XML document: " + e.text); |
9 |
}
|
Sekarang kita berada hanya melacak hal; kami memastikan kami mengkonversi data URLLoader ke XML, maka meludahkannya sebagai-adalah. Kami juga menangani kesalahan dalam kasus kita mendapatkan URL yang buruk untuk memuat. Kita bisa melakukan sesuatu pengujian di sini, tetapi untuk sekarang kita akan benar-benar hanya mencegah kesalahan menghentikan segala sesuatu, sementara masih melacak pesan.
Kami memerlukan metode umum beban, untuk memulai beban XML. Kita bisa berasumsi bahwa jika ada sudah sesuatu dimuat, kita harus membersihkan pertama, kemudian mulai beban baru. Untuk itu, kita akan tidak hanya mulai beban pada URLLoader, tetapi juga memanggil metode yang disebut clearContents untuk menghapus apa-apa yang sebelumnya dibuat di memainkannya. Kita akan mengisi yang kemudian, tapi kami akan merencanakan untuk itu dan menyebutnya, dan menciptakan metode kosong ke rumah itu.
1 |
|
2 |
public function load(url:String):void { |
3 |
clearContents(); |
4 |
_urlLoader.load(new URLRequest(url)); |
5 |
}
|
6 |
|
7 |
private function clearContents():void { |
8 |
|
9 |
}
|
Terakhir, kita perlu meng-upgrade pengujian kami. Kita perlu untuk menghapus garis-garis yang membuat tes penutup dari memainkannya di konstruktor (Aku sudah berkomentar mereka di sini sehingga Anda dapat mengidentifikasi mereka, tapi pergi ke depan dan menghapusnya. Snipet kode berikutnya fungsi ini akan memiliki mereka dihapus):
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
_covers = new Vector.<Cover>(); |
6 |
|
7 |
_coversContainer = new Sprite(); |
8 |
addChild(_coversContainer); |
9 |
|
10 |
//var test:Cover = new Cover("I am a caption", <data />, _backgroundColor);
|
11 |
//_coversContainer.addChild(test);
|
12 |
//test.x = _width / 2;
|
13 |
//test.y = _height / 2;
|
14 |
//_covers.push(test);
|
15 |
|
16 |
//trace(test.caption);
|
17 |
//trace(test.data.toXMLString());
|
18 |
//trace(test.backgroundColor);
|
19 |
|
20 |
//test.load("images/best.jpg");
|
21 |
|
22 |
_background = new Shape(); |
23 |
addChildAt(_background, 0); |
24 |
drawBackground(); |
25 |
|
26 |
scrollRect = new Rectangle(0, 0, _width, _height); |
27 |
|
28 |
_urlLoader = new URLLoader(); |
29 |
_urlLoader.addEventListener(Event.COMPLETE, onXMLLoad); |
30 |
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onXMLLoadError); |
31 |
}
|
Dan kemudian kita perlu kembali ke CoverFlowTest.as dan menambahkan panggilan untuk memuat. Lulus dalam file coverFlowImages.xml yang kami ciptakan dalam langkah terakhir.
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.backgroundColor = 0x000000; |
6 |
coverFlow.load("coverFlowImages.xml"); |
7 |
}
|
Anda harus melihat kami dokumen XML yang dilacak ke Output panel.
Langkah 23: Mengurai XML
Selanjutnya kita perlu untuk mengurai XML dan akhirnya melakukan sesuatu dengan data. Kami akan mem-parsing dalam langkah ini, dan mulai melakukan sesuatu dengan itu di langkah berikutnya.
Dalam metode onXMLLoad memainkannya, menghapus jejak dan menggantinya dengan beberapa dasar XML perulangan. Untuk sekarang, kita akan menjejaki nilai-nilai untuk memastikan kami sedang parsing mereka dengan benar.
1 |
|
2 |
private function onXMLLoad(e:Event):void { |
3 |
_xml = new XML(_urlLoader.data); |
4 |
|
5 |
var imageList:XMLList = _xml.image; |
6 |
var iLen:uint = imageList.length(); |
7 |
var imageNode:XML; |
8 |
for (var i:uint = 0; i < iLen; i++) { |
9 |
imageNode = imageList[i]; |
10 |
var src:String = imageNode.@src; |
11 |
var title:String = imageNode.@title; |
12 |
trace(src); |
13 |
trace(title); |
14 |
trace(""); |
15 |
}
|
16 |
}
|
Tidak ada sesuatu yang terlalu istimewa terjadi. Kami hanya Anda memilih semua gambar node, loop atas mereka, dan kemudian mengeluarkan atribut dari mereka. Sekarang, kita akan melakukan sesuatu dengan mereka.
Langkah 24: Membuat objek Cover
Kita akan memiliki potensi untuk memuat beberapa gambar. Akan lebih baik untuk mengontrol beban dengan memuat satu per satu waktu. Hal ini akan memaksimalkan bandwidth untuk masing-masing gambar, membiarkan gambar pertama muncul secepat mungkin, sehingga ada sesuatu untuk melihat pada layar sebelum terlalu lama. Juga, kebanyakan browser cenderung throttle jumlah permintaan secara bersamaan pula, jadi daripada membiarkan browser mengontrol itu, kita mungkin juga mengendalikannya di Flash.
Untuk bekerja dalam hal ini, kita harus benar-benar memuat beberapa gambar menjadi beberapa benda-benda penutup, jadi kita akan mulai dengan menciptakan objek Cover dan mulai beban. Kami akan kemahiran proses selama beberapa langkah berikutnya.
Dalam memainkannya 's onXMLLoad metode, kami akan menghapus jejak-jejak dan sebaliknya membuat objek penutup:
1 |
|
2 |
private function onXMLLoad(e:Event):void { |
3 |
_xml = new XML(_urlLoader.data); |
4 |
|
5 |
var imageList:XMLList = _xml.image; |
6 |
var iLen:uint = imageList.length(); |
7 |
var imageNode:XML; |
8 |
var cover:Cover; |
9 |
for (var i:uint = 0; i < iLen; i++) { |
10 |
imageNode = imageList[i]; |
11 |
var src:String = imageNode.@src; |
12 |
var title:String = imageNode.@title; |
13 |
cover = new Cover(title, imageNode, _backgroundColor); |
14 |
_coversContainer.addChild(cover); |
15 |
cover.x = i * 200 + 100; |
16 |
cover.y = 250; |
17 |
cover.load(src); |
18 |
_covers.push(cover); |
19 |
}
|
20 |
}
|
Anda akan melihat bahwa kita sedang melakukan mungkin apa yang Anda harapkan: pertama, kita membuat objek baru Cover, melewati dalam data yang diambil dari XML. Kemudian kami tambahkan ke daftar tampilan. Selanjutnya kami posisi itu; ini bersifat sementara, tetapi akan memungkinkan kita untuk melihat hasil untuk sekarang. Nilai x didasarkan pada jumlah iterasi, sehingga kita mendapatkan penempatan kiri-ke-kanan. Sekali lagi, kami akan meninjau kembali tata letak logika, ini adalah hanya untuk melihat sesuatu sekarang.
Kemudian kami memberitahu penutup untuk me-load dengan sumber gambar yang ditemukan dalam XML, dan akhirnya menyimpan penutup objek dalam kita _covers vektor.
Panggilan ini untuk memuat juga sementara; Sekarang kita hanya membuat yakin bahwa kami berhasil menciptakan objek penutup dari XML data. Kita akan melanjutkan untuk memuat gambar berikutnya secara berurutan.
Jika Anda menerbitkan sekarang, Anda harus melihat sesuatu yang setidaknya sedikit menarik:



3D tidak lagi, tapi itu akan datang. Bersabar!
Langkah 25: Memuat gambar dalam urutan
Kita akan beralih logika dari pemuatan setiap penutup segera untuk memuat mereka secara progresif. Ini akan melibatkan menjaga melacak yang counter yang menunjuk ke penutup yang saat ini sedang loading, dan fungsi yang memuat sampul berikutnya. Kami memiliki beberapa berhenti di sepanjang jalan, jadi mengikuti bersama.
Pertama, dalam Cover, kami ingin memastikan bahwa kita kembali mengirimkan peristiwa yang lengkap setelah Load gambar. Dalam onLoadComplete, tambahkan baris ini pada akhir:
1 |
|
2 |
private function onLoadComplete(e:Event):void { |
3 |
_loader.x = -Math.round(_loader.width / 2); |
4 |
_loader.y = -_loader.height; |
5 |
drawReflection(); |
6 |
dispatchEvent(e); |
7 |
}
|
Sisa perubahan kami akan terjadi dalam memainkannya. Pertama, tambahkan properti untuk melacak saat ini memuat Cover oleh indeks:
1 |
|
2 |
private var _loadCounter:uint; |
Kemudian, di onXMLLoad, kami akan menghapus var src:String =... dan cover.load(src) baris, dan set _loadCounter properti untuk 0, serta panggilan metode yang kita tidak menulis lagi:
1 |
|
2 |
private function onXMLLoad(e:Event):void { |
3 |
_xml = new XML(_urlLoader.data); |
4 |
|
5 |
var imageList:XMLList = _xml.image; |
6 |
var iLen:uint = imageList.length(); |
7 |
var imageNode:XML; |
8 |
var cover:Cover; |
9 |
for (var i:uint = 0; i < iLen; i++) { |
10 |
imageNode = imageList[i]; |
11 |
//var src:String = imageNode.@src;
|
12 |
var title:String = imageNode.@title; |
13 |
cover = new Cover(title, imageNode, _backgroundColor); |
14 |
_coversContainer.addChild(cover); |
15 |
cover.x = i * 200 + 100; |
16 |
cover.y = 250; |
17 |
//cover.load(src);
|
18 |
_covers.push(cover); |
19 |
}
|
20 |
_loadCounter = 0; |
21 |
loadNextCover(); |
22 |
}
|
Sekarang mari kita menulis metode loadNextCover. Idenya adalah untuk mengambil nilai sekarang dari _loadCounter dan menggunakannya untuk menargetkan sampul dan gambar sumber.
1 |
|
2 |
private function loadNextCover():void { |
3 |
var cover:Cover = _covers[_loadCounter]; |
4 |
var src:String = _xml.image[_loadCounter].@src; |
5 |
cover.load(src); |
6 |
cover.addEventListener(Event.COMPLETE, onCoverLoad); |
7 |
}
|
Pertama, kita mendapatkan objek Cover dibuat sebelumnya dari _covers vektor. Maka kita mendapatkan URL gambar tersebut cocok dengan kembali ke data dari XML dan menemukan gambar node menggunakan nilai yang sama dari _loadCounter. Kemudian kami hanya meminta penutup untuk memuat URL itu. Akhirnya, kita menambahkan pendengar yang lengkap, yang kita butuhkan untuk menulis berikut:
1 |
|
2 |
private function onCoverLoad(e:Event):void { |
3 |
e.target.removeEventListener(Event.COMPLETE, onCoverLoad); |
4 |
_loadCounter++; |
5 |
if (_loadCounter < _covers.length) { |
6 |
loadNextCover(); |
7 |
} else { |
8 |
dispatchEvent(new Event(Event.COMPLETE)); |
9 |
}
|
10 |
}
|
Setiap kali sebuah Cover selesai loading, mari kita pertama membersihkan diri kita dan menghapus pendengar acara lengkap. Kemudian akan kenaikan _loadCounter dan kemudian memeriksa untuk melihat apakah kita dapat masih memiliki sampul yang tersisa di _covers vektor. Jika kita lakukan, maka kita sebut loadNextCover() lagi, yang mulai proses atas lagi dengan sampul berbeda dan gambar. Jika tidak, maka kita harus pada akhir, sehingga kami dapat mengirimkan peristiwa yang lengkap.
Untuk menguji acara ini, hop kembali ke CoverFlowTest dan tambahkan kode berikut:
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.backgroundColor = 0x000000; |
6 |
coverFlow.load("coverFlowImages.xml"); |
7 |
coverFlow.addEventListener(Event.COMPLETE, onCoverFlowLoaded); |
8 |
}
|
9 |
|
10 |
private function onCoverFlowLoaded(e:Event):void { |
11 |
trace("Coverflow loaded and ready to go."); |
12 |
}
|
Ini harus langsung: kami hanya menambahkan pendengar untuk peristiwa yang lengkap yang hanya menelusuri. Pergi ke depan dan menjalankan film sekarang. Anda akan melihat gambar muncul secara berurutan, dan, setelah gambar semuanya dimuat, Anda akan melihat pesan "Memainkannya dimuat dan siap untuk pergi." di Output panel.



Langkah 26: Menentukan kemajuan
Untuk dapat mengirimkan peristiwa kemajuan seperti memuat gambar, kita akan hal-hal palsu sedikit. Kami akan menganggap bahwa gambar pertama untuk memuat, rata-rata, perwakilan dari semua gambar. Pasti akan ada kasus-kasus yang mana hal ini tidak benar, tetapi untuk untuk sebagian besar aplikasi kita akan berurusan dengan gambar sama dimensi, kualitas, dan konten, dan karena itu paling gambar akan jatuh di sekitar ukuran file yang sama.
Pertama, kita perlu mengubah metode onLoadProgress di sampul sehingga kami bisa menyingkirkan jejak dan redispatch acara berlangsung:
1 |
|
2 |
private function onLoadProgress(e:ProgressEvent):void { |
3 |
dispatchEvent(e); |
4 |
}
|
Kemudian kita akan membutuhkan dua sifat yang lebih dalam memainkannya untuk membantu melacak kemajuan keseluruhan:
1 |
|
2 |
private var _bytesPerImage:int; |
3 |
private var _bytesTotal:int; |
Sekarang, hal berikutnya yang harus dilakukan adalah mendapatkan ukuran gambar pertama setelah itu mulai loading. Kita perlu memastikan bahwa kami menambahkan pendengar acara berlangsung ketika kita mulai beban. Dalam memainkannya 's loadNextCover metode:
1 |
|
2 |
private function loadNextCover():void { |
3 |
var cover:Cover = _covers[_loadCounter]; |
4 |
var src:String = _xml.image[_loadCounter].@src; |
5 |
cover.load(src); |
6 |
cover.addEventListener(Event.COMPLETE, onCoverLoad); |
7 |
cover.addEventListener(ProgressEvent.PROGRESS, onCoverProgress); |
8 |
}
|
Dan menambahkan onCoverProgress metode:
1 |
|
2 |
private function onCoverProgress(e:ProgressEvent):void { |
3 |
if (_bytesPerImage == 0) { |
4 |
_bytesPerImage = e.bytesTotal; |
5 |
_bytesTotal = _bytesPerImage * _covers.length; |
6 |
}
|
7 |
var adjustedBytesLoaded:uint = e.bytesLoaded * (_bytesPerImage / e.bytesTotal); |
8 |
var cumulativeBytesLoaded:uint = (_loadCounter * _bytesPerImage) + adjustedBytesLoaded; |
9 |
dispatchEvent(new ProgressEvent(ProgressEvent.PROGRESS, false, false, cumulativeBytesLoaded, _bytesTotal)); |
10 |
}
|
Sekarang, untuk menguji itu, kembali ke CoverFlowTest dan menambahkan pendengar untuk kemajuan acara:
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.backgroundColor = 0x000000; |
6 |
coverFlow.load("coverFlowImages.xml"); |
7 |
coverFlow.addEventListener(Event.COMPLETE, onCoverFlowLoaded); |
8 |
coverFlow.addEventListener(ProgressEvent.PROGRESS, onCoverFlowProgress); |
9 |
}
|
10 |
|
11 |
private function onCoverFlowProgress(e:ProgressEvent):void { |
12 |
trace("Coverflow progress: " + e.bytesLoaded + " / " + e.bytesTotal); |
13 |
}
|
Dan tes film. Anda harus melihat serangkaian panjang kemajuan jejak, mengakhiri dalam pesan "load", seperti berikut:



Tentu saja, Anda akan ingin menampilkan sesuatu yang informatif di panggung, tidak jejak keluar angka. Tugas khusus ini, namun, tidak benar-benar memenuhi memainkannya; itu sudah cukup bahwa itu adalah pengiriman sesuai peristiwa. Saya tidak akan memukul penciptaan sebuah progress bar, dan sebaliknya, aku akan mengubah pekerjaan lebih menarik menampilkan meliputi dalam 3D.
Langkah 27: Refactor logika
Kita akan melihat bahwa loop yang mem-parsing XML, menciptakan objek Cover, dan meletakkan mereka. Mari kita offload logika tata letak untuk metode lain. Menghapus garis-garis dalam lingkaran yang posisi objek Cover (Anda mungkin ingin menyalinnya), dan menambahkan panggilan ke metode belum-untuk--ditulis setelah loop.
1 |
|
2 |
private function onXMLLoad(e:Event):void { |
3 |
_xml = new XML(_urlLoader.data); |
4 |
|
5 |
var imageList:XMLList = _xml.image; |
6 |
var iLen:uint = imageList.length(); |
7 |
var imageNode:XML; |
8 |
var cover:Cover; |
9 |
for (var i:uint = 0; i < iLen; i++) { |
10 |
imageNode = imageList[i]; |
11 |
var src:String = imageNode.@src; |
12 |
var title:String = imageNode.@title; |
13 |
cover = new Cover(title, imageNode, _backgroundColor); |
14 |
_coversContainer.addChild(cover); |
15 |
//cover.x = i * 200 + 100;
|
16 |
//cover.y = 250;
|
17 |
_covers.push(cover); |
18 |
}
|
19 |
layout(); |
20 |
_loadCounter = 0; |
21 |
loadNextCover(); |
22 |
}
|
Selanjutnya, menulis metode tata letak. It's lain loop, satu ini atas _covers vektor, dan internal itu logika posisi yang sama:
1 |
|
2 |
private function layout():void { |
3 |
var len:uint = _covers.length; |
4 |
var cover:Cover; |
5 |
for (var i:uint = 0; i < len; i++) { |
6 |
cover = _covers[i]; |
7 |
cover.x = i * 200 + 100; |
8 |
cover.y = 250; |
9 |
}
|
10 |
}
|
Pergi ke depan dan mengujinya sekarang; Anda harus melihat benar-benar tidak ada perubahan. Satu-satunya perbedaan adalah murni behind-the-scenes logika. Kami telah menambahkan keuntungan adalah bahwa kami akan dapat menelepon layout() setiap saat, independen dari onXMLLoad().
Langkah 28: Layout awal
Mari kita pergi untuk membayar besar sekarang. Kami akan menulis ulang tata letak logika sehingga hal itu mulai terjadi dalam 3D. Menghapus cover.x =... baris dan tambahkan baris disorot di bawah ini (masih dalam memainkannya):
1 |
|
2 |
private function layout():void { |
3 |
var len:uint = _covers.length; |
4 |
var cover:Cover; |
5 |
for (var i:uint = 0; i < len; i++) { |
6 |
cover = _covers[i]; |
7 |
if (i == 0) { |
8 |
cover.rotationY = 0; |
9 |
cover.x = _background.width / 2; |
10 |
cover.z = 0; |
11 |
} else { |
12 |
cover.rotationY = 45; |
13 |
cover.x = ((_background.width / 2) + 60) + (i * 30); |
14 |
cover.z = 150; |
15 |
}
|
16 |
cover.y = 250; |
17 |
}
|
18 |
}
|
Logika ini membutuhkan banyak cinta, tapi pergi ke depan dan jalankan sekarang, dan Anda harus melihat... sesuatu yang tidak benar.



Anda harus melihat potensi tidak, tapi jelas kita perlu mengelola kedalaman. Ini adalah kelemahan untuk menggunakan Flash's built-in kemampuan 3D: menjadikan DisplayObject masing-masing dengan benar, tetapi tidak "adegan" dari beberapa DisplayObjects. Kedalaman 2D normal susun aturan berlaku, bahkan jika "z" objek tersebut harus tempat itu sebaliknya.
Ini sedikit logika, meskipun, memberikan Anda sekilas dari apa yang akan kita lakukan: pertama, menentukan dimana dalam "aliran" penutup diberikan-terpusat, di sebelah kanan atau (akhirnya) di sebelah kiri. Kemudian mengatur x Cover, z dan sifat rotationY tepat. Matematika terlibat dalam posisi sisi kanan x adalah mulut penuh, tapi dapat dibaca seperti ini:
Mulai di pusat (_background.width / 2), memindahkan 60 piksel ke kanan untuk memberikan beberapa ruang di sekitar item terpusat (... + 60), kemudian, tergantung pada mana kita berada dalam lingkaran, pindah penutup selanjutnya ke kanan (... + (saya + 30)).
Langkah 29: Mengelola kedalaman
Mari kita selanjutnya mengatasi kedalaman masalah. Berikut adalah apa yang perlu terjadi: item terpusat perlu paling depan. Setelah itu, item di kedua sisi perlu menjadi penurunan indeks kedalaman lebih lanjut mereka berasal dari pusat. Ini adalah, Untungnya, relatif sederhana untuk mencapai. Menyesuaikan logika di memainkannya di tata letak metode:
1 |
|
2 |
private function layout():void { |
3 |
var len:uint = _covers.length; |
4 |
var cover:Cover; |
5 |
for (var i:uint = 0; i < len; i++) { |
6 |
cover = _covers[i]; |
7 |
if (i == 0) { |
8 |
cover.rotationY = 0; |
9 |
cover.x = _background.width / 2; |
10 |
cover.z = 0; |
11 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren-1); |
12 |
} else { |
13 |
cover.rotationY = 45; |
14 |
cover.x = ((_background.width / 2) + 60) + (i * 30); |
15 |
cover.z = 150; |
16 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (i + 1)); |
17 |
}
|
18 |
cover.y = 250; |
19 |
}
|
20 |
}
|
Di blok jika pertama, kita berada di tengah penutup, sehingga kami mengatur indeks penutup dengan indeks tertinggi yang tersedia. Dalam blok lain, semakin tinggi saya adalah, semakin rendah nomor indeks yang kita dapatkan. Yang bekerja dibandingkan lainnya meliputi di sebelah kanan, tetapi kita perlu untuk mencatat indeks oleh satu lagi untuk mengakomodasi pusat Cover (tertinggi).
Mencobanya sekarang... Anda akan melihat beberapa visual yang menjanjikan!



Langkah 30: Sisi kiri
OK, sejauh ini kami telah membuat asumsi yang membuatnya sangat sulit untuk meletakkan hal-hal yang nyata. Asumsi besar adalah bahwa kita sedang berpusat penutup pertama (indeks 0). Jika Anda mencoba untuk pusat, mengatakan, penutup keempat, Anda akan mendapatkan hasil yang sangat tidak diharapkan:



Ini tidak terlihat buruk pada pandangan pertama, tetapi berpikir tentang hal itu. Jika kita sedang berpusat penutup keempat, kita berharap untuk melihat tiga meliputi di sebelah kiri, satu-keempat di pusat, dan sisanya di sebelah kanan. Mari kita membuat itu terjadi.
Pertama, mari kita membuat sebuah properti baru (masih dalam memainkannya) yang akan memegang nilai indeks kami saat ini. Mari kita menyebutnya _selectedIndex.
1 |
|
2 |
private var _selectedIndex:uint; |
Dan, untuk tujuan pengujian, kami akan menetapkan nilai ke 4 di atas metode tata letak. Ini akan mendapatkan dihapus pada langkah berikutnya. Kemudian, kami akan mengolah logika dalam loop tata letak untuk menjadi sedikit lebih dinamis.
1 |
|
2 |
private function layout():void { |
3 |
_selectedIndex = 4; |
4 |
var len:uint = _covers.length; |
5 |
var cover:Cover; |
6 |
var distanceFromCenter:uint; |
7 |
for (var i:uint = 0; i < len; i++) { |
8 |
cover = _covers[i]; |
9 |
if (i == _selectedIndex) { |
10 |
cover.rotationY = 0; |
11 |
cover.x = _background.width / 2; |
12 |
cover.z = 0; |
13 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren-1); |
14 |
} else if (i < _selectedIndex) { |
15 |
distanceFromCenter = _selectedIndex - i; |
16 |
cover.rotationY = -45; |
17 |
cover.x = ((_background.width / 2) - 60) - (distanceFromCenter * 30); |
18 |
cover.z = 150; |
19 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (distanceFromCenter + 1)); |
20 |
} else if (i > _selectedIndex) { |
21 |
distanceFromCenter = i - _selectedIndex; |
22 |
cover.rotationY = 45; |
23 |
cover.x = ((_background.width / 2) + 60) + (distanceFromCenter * 30); |
24 |
cover.z = 150; |
25 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (distanceFromCenter + 1)); |
26 |
}
|
27 |
cover.y = 250; |
28 |
}
|
29 |
}
|
Itu banyak logika dan matematika, tapi itu benar-benar agak berulang-ulang. Baru blok di tengah, tapi hampir identik dengan yang lain lain jika memblokir, hanya beberapa hal dibalik. Tapi pergi ke depan dan menguji film, seharusnya terlihat seperti ini:



Perubahan besar itu pindah dari saya sebagai faktor langsung penempatan meliputi, tetapi sebaliknya menentukan jarak yang saya dari indeks saat ini. Yang lebih jauh, selanjutnya merupakan berjarak x harus dari pusat, dan juga kembali makin jauh di kedalaman telah menjadi. Matematika adalah hanya terjemahan dari apa yang kami lakukan sebelum untuk pendekatan yang lebih dinamis. Jika Anda suka, pergi ke depan dan mencoba mengatur _selectedIndex ke nilai-nilai lain, dan memastikan bahwa Anda mendapatkan hasil yang Anda harapkan.
Langkah 31: Menyesuaikan penampilan
Anda mungkin merasa bahwa distribusi mencakup adalah sedikit sempit (saya tahu saya lakukan, tetapi saya harus bekerja dalam batas lebar 600 pixel yang Activetuts + tempat saya). Bahkan, ada beberapa parameter posisi yang dapat men-tweak untuk menyesuaikan tampilan keseluruhan. Kita akan pergi ke depan dan membuat sekelompok properti, setter terkait dan pengambil, untuk menangani kustomisasi ini. Dan kita akan tentu saja menggunakan properti-properti bukan keras-kode nomor dalam metode tata letak kami.
Ini akan menjadi langkah panjang, tapi jangan takut, itu cukup mendasar.
Pertama, properti:
1 |
|
2 |
private var _centerMargin:Number; |
3 |
private var _horizontalSpacing:Number; |
4 |
private var _backRowDepth:Number; |
5 |
private var _backRowAngle:Number; |
6 |
private var _verticalOffset:Number; |
Properti ini akan mengontrol berikut:
- centerMargin kontrol jumlah ruang di kedua sisi pusat Cover dan selimut pertama ke samping. Ini harus menjadi nilai positif.
- horizontalSpacing mengontrol jumlah ruang antara meliputi dalam "kembali." Semua penutup di sebelah kiri dan kanan (tapi tidak menghitung pusat) akan memiliki jumlah yang sama ruang di antara meliputi berdekatan. Ini harus menjadi nilai positif.
- backRowDepth mengontrol seberapa jauh ke belakang barisan belakang adalah. Ini akan dalam bentuk sebuah offset, sehingga mencegah barisan belakang dari yang di depan pusat penutup. Ini harus menjadi nilai positif.
- backRowAngle kontrol sudut di mana mencakup di barisan belakang akan berubah. Ini adalah semacam nilai mutlak, dan nilai adalah "cermin" untuk sisi lainnya. Itu harus dibatasi antara 0 dan 90.
- verticalOffset kontrol jumlah yang digunakan untuk memindahkan seluruh set meliputi atas atau bawah, offset dari nilai y secara otomatis ditetapkan. Ini bisa menjadi nomor. Kita akan kembali kepada sedikit logika, tetapi kita juga dapat menulis properti, penyetel dan pengambil sementara kita lakukan yang lain empat.
Kami akan membuat konstanta mengandung nilai-nilai default dari masing-masing properti ini. Ini dapat pergi dengan sisa properti Anda:
1 |
|
2 |
private static const DEFAULT_CENTER_MARGIN:Number = 60; |
3 |
private static const DEFAULT_HORIZONTAL_SPACING:Number = 30; |
4 |
private static const DEFAULT_BACK_ROW_DEPTH:Number = 150; |
5 |
private static const DEFAULT_BACK_ROW_ANGLE:Number = 45; |
6 |
private static const DEFAULT_VERTICAL_OFFSET:Number = 0; |
Dalam konstruktor, menetapkan masing-masing properti nilai-nilai default ini (jika Anda tidak menyukai nilai-nilai default, Anda dapat mengubah mereka, bahwa bagian dari alasan untuk menempatkan mereka bersama-sama yang mudah untuk menemukan tempat). Dengan cara ini kita akan pastikan bahwa setiap variabel ini ditetapkan dengan nilai cocok bahkan jika pengguna tidak pernah ditentukan salah satu.
1 |
|
2 |
public function CoverFlow(w:Number, h:Number) { |
3 |
_width = w; |
4 |
_height = h; |
5 |
_covers = new Vector.<Cover>(); |
6 |
|
7 |
_centerMargin = DEFAULT_CENTER_MARGIN; |
8 |
_horizontalSpacing = DEFAULT_HORIZONTAL_SPACING; |
9 |
_backRowDepth = DEFAULT_BACK_ROW_DEPTH; |
10 |
_backRowAngle = DEFAULT_BACK_ROW_ANGLE; |
11 |
_verticalOffset = DEFAULT_VERTICAL_OFFSET; |
12 |
|
13 |
_coversContainer = new Sprite(); |
14 |
addChild(_coversContainer); |
15 |
|
16 |
_background = new Shape(); |
17 |
addChildAt(_background, 0); |
18 |
drawBackground(); |
19 |
|
20 |
scrollRect = new Rectangle(0, 0, _width, _height); |
21 |
|
22 |
_urlLoader = new URLLoader(); |
23 |
_urlLoader.addEventListener(Event.COMPLETE, onXMLLoad); |
24 |
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onXMLLoadError); |
25 |
}
|
Dan, dengan nilai yang valid dalam pikiran, menulis dan setter Getter (Aku akan menempatkan ini tepat setelah kami saat ini setter dan pengambil, di sekitar baris 89):
1 |
|
2 |
public function set centerMargin(num:Number):void { |
3 |
if (isNaN(num)) num = DEFAULT_CENTER_MARGIN; |
4 |
_centerMargin = Math.max(0, num); |
5 |
}
|
6 |
public function get centerMargin():Number { |
7 |
return _centerMargin; |
8 |
}
|
9 |
|
10 |
public function set horizontalSpacing(num:Number):void { |
11 |
if (isNaN(num)) num = DEFAULT_HORIZONTAL_SPACING; |
12 |
_horizontalSpacing = Math.max(0, num); |
13 |
}
|
14 |
public function get horizontalSpacing():Number { |
15 |
return _horizontalSpacing; |
16 |
}
|
17 |
|
18 |
public function set backRowDepth(num:Number):void { |
19 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_DEPTH; |
20 |
_backRowDepth = Math.max(0, num); |
21 |
}
|
22 |
public function get backRowDepth():Number { |
23 |
return _backRowDepth; |
24 |
}
|
25 |
|
26 |
public function set backRowAngle(num:Number):void { |
27 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_ANGLE; |
28 |
_backRowAngle = Math.min(90, Math.abs(num)); |
29 |
}
|
30 |
public function get backRowAngle():Number { |
31 |
return _backRowAngle; |
32 |
}
|
33 |
|
34 |
public function set verticalOffset(num:Number):void { |
35 |
if (isNaN(num)) num = DEFAULT_VERTICAL_OFFSET; |
36 |
_verticalOffset = num; |
37 |
}
|
38 |
public function get verticalOffset():Number { |
39 |
return _verticalOffset; |
40 |
}
|
Dan akhirnya kita perlu mengganti nomor tertanam di logika tata letak kami dengan sifat-sifat ini. Dalam tata letak:
1 |
|
2 |
for (var i:uint = 0; i < len; i++) { |
3 |
cover = _covers[i]; |
4 |
if (i == _selectedIndex) { |
5 |
cover.rotationY = 0; |
6 |
cover.x = _background.width / 2; |
7 |
cover.z = 0; |
8 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren-1); |
9 |
} else if (i < _selectedIndex) { |
10 |
distanceFromCenter = _selectedIndex - i; |
11 |
cover.rotationY = -_backRowAngle; |
12 |
cover.x = ((_background.width / 2) - _centerMargin) - (distanceFromCenter * _horizontalSpacing); |
13 |
cover.z = _backRowDepth; |
14 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (distanceFromCenter + 1)); |
15 |
} else if (i > _selectedIndex) { |
16 |
distanceFromCenter = i - _selectedIndex; |
17 |
cover.rotationY = _backRowAngle; |
18 |
cover.x = ((_background.width / 2) + _centerMargin) + (distanceFromCenter * _horizontalSpacing); |
19 |
cover.z = _backRowDepth; |
20 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (distanceFromCenter + 1)); |
21 |
}
|
22 |
cover.y = 250; |
23 |
}
|
Anda dapat menguji film seperti, dan hal-hal harus berfungsi persis seperti yang mereka miliki sebelumnya. Namun, Anda juga bisa menguji properti ini dengan menetapkan mereka dari CoverFlowTest. Mengatur mereka namun Anda (pada kenyataannya, pastikan untuk menguji nilai ilegal, seperti -200 untuk centerMargin), misalnya:
1 |
|
2 |
public function CoverFlowTest() { |
3 |
coverFlow = new CoverFlow(stage.stageWidth, stage.stageHeight); |
4 |
addChild(coverFlow); |
5 |
coverFlow.backgroundColor = 0x000000; |
6 |
coverFlow.horizontalSpacing = 60; |
7 |
coverFlow.centerMargin = 100; |
8 |
coverFlow.load("coverFlowImages.xml"); |
9 |
coverFlow.addEventListener(Event.COMPLETE, onCoverFlowLoaded); |
10 |
coverFlow.addEventListener(ProgressEvent.PROGRESS, onCoverFlowProgress); |
11 |
}
|



Langkah 32: Efisien Layout
Sekarang, memainkannya kami bekerja dan agak customizable, tetapi hanya jika kita mengatur nilai sebelum memuat XML file. Seperti yang sekarang, menetapkan sifat pada setiap titik setelah itu akan mengakibatkan tidak ada perubahan.
Ini bisa menjadi semudah hanya memanggil layout() dari masing-masing setter. Namun, ini rentan terhadap penggunaan yang tidak efisien siklus CPU. Jika Anda perlu untuk mengatur semua properti lima dalam satu kali kejadian, yang akan berakhir melaksanakan tata letak logika 5 kali berturut-turut, 4 pertama menjadi sia-sia karena Anda tidak melakukan setting nilai untuk apa yang Anda perlu.
Karena Flash beroperasi pada model frame dari render, dimana melaksanakan kode di antara setiap frame, dan kemudian tampilan diperbarui, kita perlu cara untuk hanya menjalankan metode tata letak ketika panggung akan diberikan untuk frame berikutnya. Ini bisa Mari kita mengatur properti sebanyak yang kita suka, tapi masih hanya redraw memainkannya sekali per frame.
Ada cara mudah untuk melakukan ini, Untungnya, tapi itu mengambil beberapa sarana. Kita perlu memanfaatkan acara RENDER. Acara RENDER akan mendapatkan Dikirim oleh DisplayObject ketika panggung adalah tentang untuk mendapatkan diterjemahkan, tapi sebelum membuat terjadi. Sebagai bonus, acara tidak pengiriman ketika Flash Player diminimalkan, berarti kita tidak boleh membuang siklus jika Anda bahkan tidak bisa melihat film.
Menerapkan ini adalah proses tiga langkah: pertama, kita perlu untuk mendengarkan acara. Dalam konstruktor memainkannya, tambahkan baris ini:
1 |
|
2 |
this.addEventListener(Event.RENDER, onRender); |
Selanjutnya, tambahkan metode pendengar:
1 |
|
2 |
private function onRender(e:Event):void { |
3 |
layout(); |
4 |
}
|
Yup, itu adalah itu... kita akan hanya menelepon tata letak setiap kali kita mendapatkan acara.
Terakhir, kita perlu menelepon membatalkan di panggung setiap kali kita ingin membuat acara datang dengan cara kami. Ini berarti bahwa setiap dari setter, kita perlu tambahkan baris ini pada akhir:
1 |
|
2 |
if (stage) stage.invalidate(); |
Jika tidak ada tahap, kita tidak ingin untuk memanggil metode dan menyebabkan kesalahan referensi objek null. Lagi pula, jika tidak ada tahap, maka objek memainkannya bukan pada tampilan daftar anyway, sehingga tidak ada gunanya meminta untuk membuat acara.
Panggilan untuk membatalkan, bagaimanapun, adalah bagaimana kita bisa membuat acara untuk api. Tanpa panggilan itu, kita tidak akan mendapatkan acara, bahkan dengan pendengar acara. Jadi, kita perlu ini dalam berbusana setiap:
1 |
|
2 |
public function set centerMargin(num:Number):void { |
3 |
if (isNaN(num)) num = DEFAULT_CENTER_MARGIN; |
4 |
_centerMargin = Math.max(0, num); |
5 |
if (stage) stage.invalidate(); |
6 |
}
|
7 |
public function get centerMargin():Number { |
8 |
return _centerMargin; |
9 |
}
|
10 |
|
11 |
public function set horizontalSpacing(num:Number):void { |
12 |
if (isNaN(num)) num = DEFAULT_HORIZONTAL_SPACING; |
13 |
_horizontalSpacing = Math.max(0, num); |
14 |
if (stage) stage.invalidate(); |
15 |
}
|
16 |
public function get horizontalSpacing():Number { |
17 |
return _horizontalSpacing; |
18 |
}
|
19 |
|
20 |
public function set backRowDepth(num:Number):void { |
21 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_DEPTH; |
22 |
_backRowDepth = Math.max(0, num); |
23 |
if (stage) stage.invalidate(); |
24 |
}
|
25 |
public function get backRowDepth():Number { |
26 |
return _backRowDepth; |
27 |
}
|
28 |
|
29 |
public function set backRowAngle(num:Number):void { |
30 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_ANGLE; |
31 |
_backRowAngle = Math.min(90, Math.abs(num)); |
32 |
if (stage) stage.invalidate(); |
33 |
}
|
34 |
public function get backRowAngle():Number { |
35 |
return _backRowAngle; |
36 |
}
|
37 |
|
38 |
public function set verticalOffset(num:Number):void { |
39 |
if (isNaN(num)) num = DEFAULT_VERTICAL_OFFSET; |
40 |
_verticalOffset = num; |
41 |
if (stage) stage.invalidate(); |
42 |
}
|
43 |
public function get verticalOffset():Number { |
44 |
return _verticalOffset; |
45 |
}
|
Jadi sekarang, jika kita mengatur properti 5 pada saat yang sama, kami mungkin membatalkan panggilan pada tahap lebih dari sekali, tapi itu baik, bahwa tidak akan menyebabkan masalah. Kita harus mendapatkan satu peristiwa RENDER sebagai akibatnya, berarti kita meletakkan keluar memainkannya hanya sekali per frame.
Untuk menguji ini, kita dapat menempatkan beberapa jejak ke metode kami, dan kemudian menetapkan properti ini setelah XML telah dimuat. Pertama, menambahkan pesan jejak ke onRender:
1 |
|
2 |
private function onRender(e:Event):void { |
3 |
trace("render") |
4 |
layout(); |
5 |
}
|
Kemudian, dalam CoverFlowTest, menetapkan semua 5 properti di onCoverFlowLoaded:
1 |
|
2 |
private function onCoverFlowLoaded(e:Event):void { |
3 |
trace("Coverflow loaded and ready to go."); |
4 |
coverFlow.horizontalSpacing = 100; |
5 |
coverFlow.centerMargin = 75; |
6 |
coverFlow.backRowDepth = 300; |
7 |
coverFlow.backRowAngle = 75; |
8 |
coverFlow.verticalOffset = 50; |
9 |
}
|
Anda harus melihat film memuat gambar seperti sebelumnya, namun, kali ini, gambar harus melompat ke tata letak yang sedikit berbeda setelah semua gambar telah dimuat. Ini membuktikan bahwa hal-hal bekerja secara visual, tetapi lebih penting lagi, periksa Output panel. Anda akan melihat pesan "membuat" tunggal. Kita dipanggil stage.invalidate dari setter 5, tapi yang mengakibatkan hanya satu RENDER peristiwa, yang adalah apa yang kita setelah.
Merasa bebas untuk menghapus jejak dan kode tata letak kami hanya menambahkan.
Langkah 33: berkumpul kembali
Sudah beberapa saat sejak saya telah terdaftar kode kelas penuh. Pekerjaan kami telah terutama memainkannya. Inilah keadaan saat ini dengan kelas:
1 |
|
2 |
package com.tutsplus.coverflow { |
3 |
|
4 |
import flash.display.*; |
5 |
import flash.geom.*; |
6 |
import flash.events.*; |
7 |
import flash.net.*; |
8 |
import flash.text.*; |
9 |
import flash.utils.*; |
10 |
|
11 |
public class CoverFlow extends Sprite { |
12 |
|
13 |
private var _coversContainer:Sprite; |
14 |
private var _width:Number; |
15 |
private var _height:Number; |
16 |
private var _backgroundColor:uint = 0; |
17 |
private var _background:Shape; |
18 |
private var _covers:Vector.<Cover>; |
19 |
private var _urlLoader:URLLoader; |
20 |
private var _xml:XML; |
21 |
private var _loadCounter:uint; |
22 |
private var _bytesPerImage:int; |
23 |
private var _bytesTotal:int; |
24 |
private var _selectedIndex:uint; |
25 |
private var _centerMargin:Number; |
26 |
private var _horizontalSpacing:Number; |
27 |
private var _backRowDepth:Number; |
28 |
private var _backRowAngle:Number; |
29 |
private var _verticalOffset:Number; |
30 |
|
31 |
private static const DEFAULT_CENTER_MARGIN:Number = 60; |
32 |
private static const DEFAULT_HORIZONTAL_SPACING:Number = 30; |
33 |
private static const DEFAULT_BACK_ROW_DEPTH:Number = 150; |
34 |
private static const DEFAULT_BACK_ROW_ANGLE:Number = 45; |
35 |
private static const DEFAULT_VERTICAL_OFFSET:Number = 0; |
36 |
|
37 |
public function CoverFlow(w:Number, h:Number) { |
38 |
_width = w; |
39 |
_height = h; |
40 |
_covers = new Vector.<Cover>(); |
41 |
|
42 |
_centerMargin = DEFAULT_CENTER_MARGIN; |
43 |
_horizontalSpacing = DEFAULT_HORIZONTAL_SPACING; |
44 |
_backRowDepth = DEFAULT_BACK_ROW_DEPTH; |
45 |
_backRowAngle = DEFAULT_BACK_ROW_ANGLE; |
46 |
_verticalOffset = DEFAULT_VERTICAL_OFFSET; |
47 |
|
48 |
_coversContainer = new Sprite(); |
49 |
addChild(_coversContainer); |
50 |
|
51 |
_background = new Shape(); |
52 |
addChildAt(_background, 0); |
53 |
drawBackground(); |
54 |
|
55 |
scrollRect = new Rectangle(0, 0, _width, _height); |
56 |
|
57 |
_urlLoader = new URLLoader(); |
58 |
_urlLoader.addEventListener(Event.COMPLETE, onXMLLoad); |
59 |
_urlLoader.addEventListener(IOErrorEvent.IO_ERROR, onXMLLoadError); |
60 |
|
61 |
this.addEventListener(Event.RENDER, onRender); |
62 |
}
|
63 |
|
64 |
override public function set width(num:Number):void { |
65 |
_width = num; |
66 |
_background.width = _width; |
67 |
scrollRect = new Rectangle(0, 0, _width, _height); |
68 |
}
|
69 |
override public function get width():Number { |
70 |
return _width; |
71 |
}
|
72 |
override public function set height(num:Number):void { |
73 |
_height = num; |
74 |
_background.height = _height; |
75 |
scrollRect = new Rectangle(0, 0, _width, _height); |
76 |
}
|
77 |
override public function get height():Number { |
78 |
return _height; |
79 |
}
|
80 |
|
81 |
public function set backgroundColor(val:uint):void { |
82 |
_backgroundColor = val; |
83 |
drawBackground(); |
84 |
for each (var cover:Cover in _covers) { |
85 |
cover.backgroundColor = val; |
86 |
}
|
87 |
}
|
88 |
public function get backgroundColor():uint { |
89 |
return _backgroundColor; |
90 |
}
|
91 |
|
92 |
public function set centerMargin(num:Number):void { |
93 |
if (isNaN(num)) num = DEFAULT_CENTER_MARGIN; |
94 |
_centerMargin = Math.max(0, num); |
95 |
if (stage) stage.invalidate(); |
96 |
}
|
97 |
public function get centerMargin():Number { |
98 |
return _centerMargin; |
99 |
}
|
100 |
|
101 |
public function set horizontalSpacing(num:Number):void { |
102 |
if (isNaN(num)) num = DEFAULT_HORIZONTAL_SPACING; |
103 |
_horizontalSpacing = Math.max(0, num); |
104 |
if (stage) stage.invalidate(); |
105 |
}
|
106 |
public function get horizontalSpacing():Number { |
107 |
return _horizontalSpacing; |
108 |
}
|
109 |
|
110 |
public function set backRowDepth(num:Number):void { |
111 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_DEPTH; |
112 |
_backRowDepth = Math.max(0, num); |
113 |
if (stage) stage.invalidate(); |
114 |
}
|
115 |
public function get backRowDepth():Number { |
116 |
return _backRowDepth; |
117 |
}
|
118 |
|
119 |
public function set backRowAngle(num:Number):void { |
120 |
if (isNaN(num)) num = DEFAULT_BACK_ROW_ANGLE; |
121 |
_backRowAngle = Math.min(90, Math.abs(num)); |
122 |
if (stage) stage.invalidate(); |
123 |
}
|
124 |
public function get backRowAngle():Number { |
125 |
return _backRowAngle; |
126 |
}
|
127 |
|
128 |
public function set verticalOffset(num:Number):void { |
129 |
if (isNaN(num)) num = DEFAULT_VERTICAL_OFFSET; |
130 |
_verticalOffset = num; |
131 |
if (stage) stage.invalidate(); |
132 |
}
|
133 |
public function get verticalOffset():Number { |
134 |
return _verticalOffset; |
135 |
}
|
136 |
|
137 |
private function drawBackground():void { |
138 |
_background.graphics.clear(); |
139 |
_background.graphics.beginFill(_backgroundColor, 1); |
140 |
_background.graphics.drawRect(0, 0, _width, _height); |
141 |
}
|
142 |
|
143 |
private function layout():void { |
144 |
_selectedIndex = 4; |
145 |
var len:uint = _covers.length; |
146 |
var cover:Cover; |
147 |
var distanceFromCenter:uint; |
148 |
for (var i:uint = 0; i < len; i++) { |
149 |
cover = _covers[i]; |
150 |
if (i == _selectedIndex) { |
151 |
cover.rotationY = 0; |
152 |
cover.x = _background.width / 2; |
153 |
cover.z = 0; |
154 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren-1); |
155 |
} else if (i < _selectedIndex) { |
156 |
distanceFromCenter = _selectedIndex - i; |
157 |
cover.rotationY = -_backRowAngle; |
158 |
cover.x = ((_background.width / 2) - _centerMargin) - (distanceFromCenter * _horizontalSpacing); |
159 |
cover.z = _backRowDepth; |
160 |
_coversContainer.setChildIndex(cover, _coversContainer.numChildren - (distanceFromCenter + 1)); |
161 |
} else if (i > _selectedIndex) { |
162 |
distanceFromCenter = i - _selectedIndex; |
163 |
cover.rotationY = _backRowAngle; |
164 |
cover.x = ((_background.width / 2) + _centerMargin) + (distanceFromCenter * _horizontalSpacing); |
165 |
cover |