สำหรับในตอนนี้เราจะต่อในส่วนของการเลือกรูปภาพเพื่อเปลี่ยนภาพโพรไฟล์ต่อจาก
ตอนที่แล้วที่ค้างไว้
แสดงเมนูตัวเลือก Action Sheet ใน app ionic material
https://www.ninenik.com/content.php?arti_id=744 via @ninenik
สิ่งที่เราจะต้องทำต่อคือ เมื่อมีเมนูให้เลือกหลังจากคลิกเลือกเพื่อเปลี่ยนรูปโพรไฟล์
แล้วเราจะทำการเลือกรูปภาพใหม่จากสองกรณีคือ ถ่ายรูปใหม่ และเลือกจากอัลบั้มรูป
ที่มีในเครื่องแล้ว รูปภาพประกอบเมนูที่ขึ้นแสดงจากตอนที่แล้ว
ก่อนอื่นเริ่มต้นให้เราติดตั้ง Camera Plugin
1. ติดตั้ง Camera Plugin
ด้วยคำสั่ง
cordova plugin add cordova-plugin-camera
2. ปรับไฟล์ profile.html เพื่อการแสดงผลเล็กน้อย
ให้เปิดไฟล์ profile.html ในโฟลเดอร์ templates และเพิ่มโค้ดแสดงค่า ตัวแปร
ที่ระบุตำแหน่งของไฟล์รูปภาพที่เราได้มา เพื่อให้เห็นภาพมากขึ้น
<ion-view view-title="Profile"> <ion-content ng-class="{expanded:$scope.isExpanded}"> <div class="hero slide-up" style="background-image: url('img/profile-bg.jpg');"> <div class="content"> <div id="avatar_img" class="avatar" ng-click="changeprofile()" style="background-image: url('img/daenerys.jpg');" ></div> <h3><a class="light">{{member_user}}</a></h3> <h4>{{member_phone}}</h4> </div> </div> <div class="padding"> File URI: {{fileProfile}} </div> </ion-content> </ion-view>
จะเห็นว่าเราเพิ่มการแสดงผลตัวแปร fileProfile ที่เป็นตำแหน่งของไฟล์ ที่เราได้มา
จาก FILE_URI โดยค่าที่ได้จะเป็นตำแหน่งของไฟล์ cache
3. รู้จักวิธีการเรียกใช้งานคำสั่งจาก Camera Plugin
เรามาดูตัวอย่างในส่วนของคำสั่งที่เราจะใช้
// เราจะกำหนดตัวแปรสำหรับเก็บค่าเริ่มต้น จะใช้ภาพจากอะไร เริ่มต้นใช้จากกล้อง คือถ่ายรูปใหม่ var pic_source = Camera.PictureSourceType.CAMERA; if(index==1){ // ถ้าเลือกถ่ายรูป ให้ใช้ภาพจาก CAMERA pic_source = Camera.PictureSourceType.CAMERA; } if(index==2){ // ถ้าเลือกรูปจากอัลบั้ม ให้ใช้ภาพจาก SAVEDPHOTOALBUM pic_source = Camera.PictureSourceType.SAVEDPHOTOALBUM; } // ในกรณีตัวอย่างเรามีปุ่มแค่ 3 เมนู ซึ่งค่าที่เท่ากับ 3 คือยกเลิกหรือไม่เลือกภาพ if(index!=3){ // ดังนั้นคำสั่งเลือกรูปภาพ เราจะให้ทำงานเมื่อไม่ใช้ยกเลิก หรือก็คือเมื่อไม่เท่ากับ 3 // ค่ากรณียกเลิกอาจจะไม่ใช้เลข 3 เสมอไปขึ้นอยู่กับจำนวนเมนูใน action sheet ที่เรากำหนด var options = { quality: 100, destinationType: Camera.DestinationType.FILE_URI, sourceType: pic_source, allowEdit: false, encodingType: Camera.EncodingType.JPEG, targetWidth: 200, targetHeight: 200, mediaType: Camera.MediaType.PICTURE, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false, correctOrientation:true }; $cordovaCamera.getPicture(options).then(function(imageData) { $scope.fileProfile = imageData; // กำหนด object รูปไว้ในตัวแปร เพื่อแสดงค่า var imageAvatar = document.getElementById('avatar_img'); imageAvatar.style.backgroundImage = "url('"+imageData+"')"; // นำรูปไปเป็น background }, function(err) { // error }); }
จากตัวอย่างการใช้งานข้างต้น เริ่มจากเราจะตรวจสอบค่าปุ่มเมนูที่เลือก
จากนั้น ก็จะใช้มาเป็นตัวกำหนดการตั้งค่าให้กับ ที่มาของรูปที่เราจะใช้งาน ซึ่งได้แก่
CAMERA และ SAVEDPHOTOALBUM หรือก็คือใช้รูปจากการถ่ายรูปใหม่ ถ้าเลือก
เมนูที่ 1 และใช้รูปจากการรูปที่บันทึกในอัลบั้มถ้าเลือกเมนูที่ 2 โดยใช้ตัวแปร
pic_source เป็นตัวเก็บค่า เพื่อไปใช้ในส่วนของการกำหนด option เพิ่มเติม
ส่วนของ option ประกอบด้วย
quality ระบุเป็นตัวเลข
ใช้กำหนดคุณภาพของรูป ค่าระหว่าง 0 - 100 มีผลกรณีไฟล์ JPEG
destinationType ระบุเป็นตัวเลขหรือค่าตามตัวแปร
กำหนดประเภทข้อมูลที่ต้องการคืนค่ากลับมา ได้แก่
DATA_URL กำหนดเป็นเลข 0 หรือใช้ค่า Camera.DestinationType.DATA_URL
FILE_URI กำหนดเป็น 1 หรือใช้ค่า Camera.DestinationType.FILE_URI
NATIVE_URI กำหนดเป็น 2 หรือใช้ค่า Camera.DestinationType.NATIVE_URI
อย่างไรก็ตาม การใช้รูปแบบการคืนค่ากลับมาเป็นแบบ DATA_URL นั้น จะเป้นการส่งกลับค่า
การเข้ารหัสรูปแบบเป็น string ด้วย base64 encoding ซึ่งจะทำให้ใช้งาาน ความจำเครื่อง
หรือแรมของเครื่องเป็นอย่างมากเขาจึงแนะนำให้ไปใช้ แบบ FILE_URI หรือ NATIVE_URI
แทน ใน android ค่า FILE_URI และ NATIVE_URI จะเป็นค่าเดียวกัน ดังนั้นเราจะใช้เป็นแบบ
FILE_URI
sourceType ระบุเป็นตัวเลขหรือค่าตามตัวแปร
กำหนดว่าจะใช้รูปภาพจากแหล่งไหน ถ่ายรูปใหม่ หรือ อัลบั้มรูป
PHOTOLIBRARY กำหนดเป็นเลข 0 หรือใช้ค่า Camera.PictureSourceType.PHOTOLIBRARY
CAMERA กำหนดเป็นเลข 1 หรือใช้ค่า Camera.PictureSourceType.CAMERA
SAVEDPHOTOALBUM กำหนดเป็นเลข 2 หรือใช้ค่า Camera.PictureSourceType.SAVEDPHOTOALBUM
เราสามารถใช้ Camera.PictureSourceType.SAVEDPHOTOALBUM แทน
Camera.PictureSourceType.PHOTOLIBRARY เนื่องจากเป็นค่าเดียวกันใน android
allowEdit ระบุเป็น true หรือ false
กำหนดหให้อนุญาตทำการแก้ไขไฟล์หลังจากได้ไฟล์มาแล้วหรือไม่ เช่นสมมติเราเลือกไฟล์มาแล้วหรือ
เราถ่ายรูปมาแล้ว มีการปรับขนาดของรูป ถ้ากำหนดเป็น true ก็จะขึ้นให้เราเลือกโปรแกรมแก้ไขภาพนั้นๆ
ก่อน แล้วจึงนำภาพไปใช้ แต่ถ้ากำหนดเป็น false รูปที่เราได้มาจะถูกนำไปใช้ทันทีโดยไม่มีการแก้ไข
encodingType ระบุเป็นตัวเลขหรือค่าตามตัวแปร
กำหนดฟอร์แมทรูปแบบของไฟล์รูปภาพที่เราต้องการ
JPEG กำหนดเป็นเลข 0 หรือใช้ค่า Camera.EncodingType.JPEG
PNG กำหนดเป็นเลข 1 หรือใช้ค่า Camera.EncodingType.PNG
targetWidth ระบุเป็นตัวเลข หน่วยจะหมายถึง pixelsใชร่วมกับ targetHeight
targetHeight ระบุเป็นตัวเลข หน่วยจะหมายถึง pixelsใชร่วมกับ targetWidth
mediaType ระบุเป็นตัวเลขหรือค่าตามตัวแปร
กำหนดประเภทของไฟล์ที่ต้องการให้สามารถเลือกได้กรณีเลือกรูปจากอัลบั้ม
PICTURE กำหนดเป็นเลข 0 หรือใช้ค่า Camera.MediaType.PICTURE
VIDEO กำหนดเป็นเลข 1 หรือใช้ค่า Camera.MediaType.VIDEO
ALLMEDIA กำหนดเป็นเลข 2 หรือใช้ค่า Camera.MediaType.ALLMEDIA
โดย mediaType จะทำงานกรณีเป็นการเลือกรูปจากอัลบั้มหรือไฟล์ที่บันทึกไว้แล้ว
โดยจะแสดงเฉพาะประเภทของไฟล์ที่กำหนด ให้เราเลือก
cameraDirection ระบุเป็นตัวเลขหรือค่าตามตัวแปร
ใช้กำหนดตำแหน่งของกล้องว่าใช้เป็นกล้องหน้าหรือกล้องหลัง ถ้าไม่มีการกำหนด
ในส่วนนี้จะใช้ค่าเริ่มต้นเป็นกล้องหลัง
BACK กำหนดเป็นเลข 0 หรือใช้ค่า Camera.Direction.BACK
FRONT กำหนดเป็นเลข 1 หรือใช้ค่า Camera.Direction.FRONT
saveToPhotoAlbum ระบุเป็น true หรือ false
กำหนดให้หลังจากถ่ายรูปมาแล้วให้ทำการบันทึกไว้ในอัลบั้มรูปด้วยหรือไม่
correctOrientation ระบุเป็น true หรือ false
กำหนดให้จัดการการจับภาพให้ถูกต้องตามการหมุนของเครื่องขณะใช้งาน
การใช้งานเพิ่มเติม สามารถดูได้ที่ https://github.com/apache/cordova-plugin-camera
4. ปรับแต่งในในส่วนของการเรียกใช้งาน ใน ProfileCtrl Controller
ให้เปิดไฟล์ controllers.js ในโฟลเดอร์ js แล้วดูในส่วนของ ProfileCtrl Controller
ปรับโค้ดให้เป็นดังนี้
.controller('ProfileCtrl', function( $scope, $stateParams, $timeout, ionicMaterialMotion, ionicMaterialInk, $ionicPlatform, $cordovaSpinnerDialog, $cordovaToast, $cordovaActionSheet, $cordovaCamera) { $scope.$parent.showHeader(); $scope.$parent.clearFabs(); $scope.isExpanded = false; $scope.$parent.setExpanded(false); $scope.$parent.setHeaderFab(false); $scope.$parent.hasShadow(); // กำหนดตัวแปรสำหรับค่าเริ่มต้นของข้อมูลหน้าโพรไลฟ์ $scope.member_user = ''; $scope.member_phone = ''; // กำหนดให้แสดงเมนูสมาชิก $scope.$parent.setMemberMenu(true); // สร้างฟังก์ชั่นสำหรับเรียกใช้ Toast plugin $scope.showToast = function(str, duration, position){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin return $cordovaToast .show(str, duration, position) .then(function(success) { // success }, function (error) { // error }); }); }; var db = null; $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // ตรวจสอบและทำการเชื่อมต่อกับ db db = window.sqlitePlugin.openDatabase({ name: 'my.db', location: 'default' }, function (db) { // เชื่อมต่อ db สำเร็จ $scope.showToast('Open DB Success','long','bottom'); // แสดง spin dialog plugin จะใช้หรือไม่ก็ได้ นำมาใช้เผื่อใครไปประยุกต์เพิ่ม $cordovaSpinnerDialog.show(null,"รอสักครู่..กำลังโหลดข้อมูล"); // แสดง loading $timeout(function() { // ซ่อนอัตโนมัติใน 300 มิลลิวินาที $cordovaSpinnerDialog.hide(); }, 300); // เริ่มทำงานของคำสั่ง db db.transaction(function (tx) { // เตรียมคำสั่ง sql ดึงข้อมูลสมาชิกอิงจาก member_id ที่เราเก็บไว้ใน $scope หลัก var query = "SELECT member_user, member_phone" + " FROM member WHERE member_id = ?"; // ดึงค่า member_id จาก $scope หลักด้วยฟังก์ชั่น getMemberID() var id_member = $scope.$parent.getMemberID(); // ทำคำสั่ง sql ดึงข้อมูลตาม member_id tx.executeSql(query, [id_member], function (tx, resultSet) { // ถ้าพบข้อมูล if(resultSet.rows.length){ // นำข้อมูลที่ได้ มาไว้ในตัวแปร member_user และ member_phone // เพื่อแสดงในหน้า profile $scope.member_user = resultSet.rows.item(0).member_user; $scope.member_phone = resultSet.rows.item(0).member_phone; } $cordovaSpinnerDialog.hide(); }, function (tx, error) { $scope.showToast('SELECT error: ' + error.message,'long','bottom'); }); }, function (error) { $scope.showToast('transaction error: ' + error.message,'long','bottom'); }, function () { $scope.showToast('transaction ok','long','bottom'); }); }, function (error) { $scope.showToast('Open database ERROR: ' + JSON.stringify(error),'long','bottom'); }); }); // สร้างตัวแปรสำหรับ เก็บค่าตำแหน่งของไฟล์รูปที่เราได้ $scope.fileProfile = ""; // กำหนด options การตั้งค่าการแสดงเมนูตัวเลือกใน action sheet var options = { title: 'เปลี่ยนรูปโพรไฟล์?', buttonLabels: ['ถ่ายรูป', 'เลือกจากอัลบั้ม'], addCancelButtonWithLabel: 'ยกเลิก', androidEnableCancelButton : true, winphoneEnableCancelButton : true }; // สร้างฟังก์ชั่นสำหรับแสดง action sheet ที่เราเรียกใช้ในไฟล์ profile.html $scope.changeprofile = function(){ $ionicPlatform.ready(function() { // เตรียมก่อนเรียกใช้ plugin // เรียกให้ action sheet แสดง $cordovaActionSheet.show(options) .then(function(btnIndex) { // เมื่อแสดงแล้ว และเลือกเมนู หรือยกเลิก คืนค่า key var index = btnIndex; //alert(index);// ทดสอบแสดงค่า key var pic_source = Camera.PictureSourceType.CAMERA; if(index==1){ pic_source = Camera.PictureSourceType.CAMERA; } if(index==2){ pic_source = Camera.PictureSourceType.SAVEDPHOTOALBUM; } if(index!=3){ var options = { quality: 100, destinationType: Camera.DestinationType.FILE_URI, sourceType: pic_source, allowEdit: true, encodingType: Camera.EncodingType.JPEG, targetWidth: 200, targetHeight: 200, mediaType: Camera.MediaType.PICTURE, popoverOptions: CameraPopoverOptions, saveToPhotoAlbum: false, correctOrientation:true }; $cordovaCamera.getPicture(options).then(function(imageData) { $scope.fileProfile = imageData; var imageAvatar = document.getElementById('avatar_img'); imageAvatar.style.backgroundImage = "url('"+imageData+"')"; }, function(err) { // error }); } }); }); }; $timeout(function() { ionicMaterialMotion.slideUp({ selector: '.slide-up' }); }, 300); $timeout(function() { ionicMaterialMotion.fadeSlideInRight({ startVelocity: 3000 }); }, 700); ionicMaterialInk.displayEffect(); })
จะเห็นว่าเรามีการเรียกใช้งาน $cordovaCamera โดย inject เข้าไปใน controller ต่อจาก action sheet
.controller('ProfileCtrl', function( $scope, $stateParams, $timeout, ionicMaterialMotion, ionicMaterialInk, $ionicPlatform, $cordovaSpinnerDialog, $cordovaToast, $cordovaActionSheet, $cordovaCamera) {
การทำงานก็คือเมื่อเราเลือกถ่ายรูป จะขึ้น app ให้เราเลือกใช้งานในการถ่ายรูป โดยถ้าไม่มี app ถ่ายรูป
อื่นๆ ในเครื่อง ก็จะเปิดใช้งาน app camera ในเครื่องนั้นทันที แต่ถ้ามี app ถ่ายรูปอื่นๆอยู่ด้วย ก็จะแสดง
app ให้เลือก จากนั้นเมื่อทำการถ่ายรูปที่ต้องการแล้ว ถ้ากำหนดให้แก้ไขหลังถ่ายรูป ก็จะขึ้น app ให้เราเลือก
เพื่อทำการแก้ไขรูป เมื่อทำงานเสร็จ รูปก็จะมาแสดงในตำแหน่งรูปโพรไฟล์ ซึ่งในที่นี้เรากำหนดเป็นให้แสดง
เป็นรูปพื้นหลัง และเช่นเดียวกันในกรณีเลือกเป็นเลือกรูปจากอัลบั้มรูป ก็จะขึ้น app gallery ให้เราเลือกเพื่อที่
จะเข้าไปเลือกรูป หลังจากเลือกรูป ถ้าไม่มีการกำหนดให้แก้ไข รูปก็จะถูกนำไปแสดงเป็นพื้นหลังรูปโพรไฟล์
และก็จะแสดงตำแหน่งของรูปในเครื่อง เพื่อให้เห็นภาพการทำงาน
อย่างไรก็ตามเนื้อหาในตอนนี้ เราจะให้เห็นแค่การได้มาซึ่งรูปภาพเท่านั้น นั่นคือรูปภาพจะแสดงเพียงชั่วคราว
เพราะเป็นรูปที่อยู่ใน cache ไม่ได้เป็นรูปที่บันทึกถาวร และไม่ได้เรียกใช้จากตำแหน่งไฟล์ที่แท้จริง
โดยเนื้อหาตอนต่อไป เราจะทำความรู้จักกับ ระบบไฟล์เพิ่มเติม และจะทำการเรียกใช้งาน File plugin เพื่อที่
จะทำการบันทึกรูปภาพที่ได้ลงในเครื่อง และนำไปใช้ต่อไป
5. ทำการ build apk ไฟล์แล้วนำไปทดสอบติดตั้งบนมือถือ
ด้วยคำสั่ง
C:\phonegap\learn004>phonegap build android
ให้ทำการทดสอบติดตั้งในมือถือ android ของเรา จะได้หน้าตา app ประมาณนี้