IntelliJ IDEAã§Scala on Android using sbt Part.3ï¼»ã®ã£ã©ãªã¼ã¢ããªï¼½
ãã¡ãã®è¨äºãåèã«ãç»åãé çªã«è¡¨ç¤ºããã ãã®ç°¡åãªã®ã£ã©ãªã¼ã¢ããªãæ¸ãã¾ããã
IDEã¯IntelliJ IDEA CE 2016.2ã§ããã«ããã¼ã«ã¯sbt 0.13.12ã使ã£ã¦ãã¾ãã
åä½ç¢ºèªã¯ãAPI level 23ã®Androidã¨ãã¥ã¬ã¼ã¿ã§å®æ½ãã¾ããã
ç®æ¬¡
Scala on Androidã§ã®ã£ã©ãªã¼ã¢ããª
å·¦å³ã®ã¹ã¯ã¤ãã§ãSDã«ã¼ãã«ä¿åãããç»åãé çªã«è¡¨ç¤ºããã ãã®ã¢ããªã§ãã
ã½ã¼ã¹ã³ã¼ããGitHubã«ç½®ãã¦ã¾ãã®ã§ãåããã¦ã¿ãå ´åã¯ãã¡ãã®è¨äºãåèã«ãã¦ä¸ããã
ããã¸ã§ã¯ããã£ã¬ã¯ããªã®æ§æ
~/PictureGallery
|- build.sbt // sbtã®ãã«ãå®ç¾©ãã¡ã¤ã«
|- /project // sbté¢é£ã®è¨å®ãã¡ã¤ã«ãé
ç½®ãããã£ã¬ã¯ããª
|- /src // ã¢ããªã®ã¢ã¸ã¥ã¼ã«ãæ§æãããã£ã¬ã¯ããª
| |- /main // ã¢ããªã®ã¡ã¤ã³ã½ã¼ã¹ã»ãããé
ç½®ãããã£ã¬ã¯ããª
| | |- AndroidManifest.xml // ã¢ããªã«é¢ããæ
å ±ãè¨è¿°ãããããã§ã¹ããã¡ã¤ã«
| | |- /libs // å¤é¨ã©ã¤ãã©ãªãé
ç½®ãããã£ã¬ã¯ããª
| | |- /res // ãªã½ã¼ã¹ãã¡ã¤ã«ãé
ç½®ãããã£ã¬ã¯ããª
| | | |- /drawable-mdpi // ä¸è§£å度ã®ç»åãé
ç½®ãããã£ã¬ã¯ããª
| | | |- /drawable-hdpi // é«è§£å度ã®ç»åãé
ç½®ãããã£ã¬ã¯ããª
| | | |- /drawable-xhdpi // è¶
é«è§£å度ã®ç»åãé
ç½®ãããã£ã¬ã¯ããª
| | | | |- ic_launcher.png // ã¢ããªã®ã¢ã¤ã³ã³ç»å
| | | |- /drawable-xxhdpi // è¶
è¶
é«è§£å度ã®ç»åãé
ç½®ãããã£ã¬ã¯ããª
| | | |- /drawable-xxxhdpi // è¶
è¶
è¶
é«è§£å度ã®ç»åãé
ç½®ãããã£ã¬ã¯ããª
| | | |- /layout // ã¬ã¤ã¢ã¦ãã®å®ç¾©ãã¡ã¤ã«ãé
ç½®ãããã£ã¬ã¯ããª
| | | | |- activity_main.xml // ç»é¢ã¬ã¤ã¢ã¦ãã®å®ç¾©ãã¡ã¤ã«
| | | |- /values // é
è²ãæåã®å®ç¾©ãã¡ã¤ã«ãé
ç½®ãããã£ã¬ã¯ããª
| | |
| | |- /scala // Scalaã®ã³ã¼ããé
ç½®ãããã£ã¬ã¯ããª
| | |- /com.b0npu.picturegallery // ã¢ããªã®ããã±ã¼ã¸ãã£ã¬ã¯ããª
| | |- PictureViewerActivity.scala // ã¢ããªã®ã¡ã¤ã³ãã¡ã¤ã«
| | |- GalleryPagerAdapter.scala // Viewã®è¡¨ç¤ºã管çããã¯ã©ã¹
| |
| |- /test // ãã¹ãã³ã¼ããé
ç½®ãããã£ã¬ã¯ããª
|
|- /target // ãã«ãã§çæãããææç©ã®åºåå
ãã£ã¬ã¯ããª
主ãªã½ã¼ã¹ã³ã¼ã
PictureViewerActivity.scala
ã®viewGalleryPager
ã¡ã½ããã§ViewPager
ãçæãã¦ãã¬ã¤ã¢ã¦ãã«è¨ç½®ãã¦ãã¾ãã
ViewPager
ã«è¨ç½®ããImageView
ã®çæã¨ImageView
ã¸ã®ç»åã®è¨ç½®ã¯Adapterã¯ã©ã¹ãè¨è¿°ããGalleryPagerAdapter.scala
ã§ç®¡çãã¦ãã¾ãã
GalleryPagerAdapter
ã¯ã©ã¹ã®addPicture
ã¡ã½ããã§ã¯ãç´æ¥é
åã«ç»åãæ ¼ç´ãã¦ã¾ãã®ã§ãç»åã®ææ°ãå¤ããªãã¨éããªãããããã¾ããã
ã¢ããªåã¯ãres/values/strings.xmls
ã®app_name
ã¨ãbuild.sbt
ã®name :=
ã§å®ç¾©ãã¦ãã¾ãã
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.b0npu.picturegallery"> <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> <application android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme"> <activity android:name="com.b0npu.picturegallery.PictureViewerActivity"> <intent-filter> <action android:name="android.intent.action.MAIN"/> <category android:name="android.intent.category.LAUNCHER"/> </intent-filter> </activity> </application> </manifest>
PictureViewerActivity.scala
package com.b0npu.picturegallery import android.Manifest import android.content.pm.PackageManager import android.content.{ContentResolver, ContentUris, DialogInterface, Intent} import android.database.Cursor import android.graphics.Bitmap import android.net.Uri import android.os.Bundle import android.provider.{BaseColumns, MediaStore, Settings} import android.support.v4.app.ActivityCompat import android.support.v4.content.PermissionChecker import android.support.v4.view.ViewPager import android.support.v7.app.{AlertDialog, AppCompatActivity} class PictureViewerActivity extends AppCompatActivity with TypedFindView { /** * ãã£ã¼ã«ãã®å®ç¾© * * requestPermissionsã¡ã½ããã§æ¨©éãè¦æ±ããéã« * ã³ã¼ã«ããã¯ã¡ã½ããã®onRequestPermissionsResultã¡ã½ããã«æ¸¡ãå®æ°ãå®ç¾© * (èªã¯ã©ã¹ã§ä½¿ãã ãã®ãã£ã¼ã«ãã¯privateã«ãã¦æ示çã«éå ¬éã«ãã¦ã¾ã) */ private val REQUEST_READ_STORAGE_PERMISSION_CODE: Int = 0x01 /** * ã¢ããªã®ç»é¢ãçæ * * ã¢ããªãèµ·åããã¨onCreateãå¼ã°ãã¦Activityãåæåããã * ç»åã®è¡¨ç¤ºã«å¿ è¦ãªãã¼ããã·ã§ã³(SDã«ã¼ãã®ãã¼ã¿ã®èªã¿è¾¼ã¿)ã確èªã㦠* ãã¼ããã·ã§ã³ã許å¯ããã¦ããªãå ´åã¯requestReadStoragePermissionã¡ã½ãã㧠* ãã¼ããã·ã§ã³ã®è¨±å¯ãè¦æ±ãã * ãã¼ããã·ã§ã³ã許å¯ããã¦ããã°viewGalleryPagerã¡ã½ããã§ç»åã表示ãã */ override def onCreate(savedInstanceState: Bundle): Unit = { super.onCreate(savedInstanceState) if (PermissionChecker.checkSelfPermission(PictureViewerActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED) { requestReadStoragePermission } else { viewGalleryPager } } /** viewGalleryPagerã¡ã½ããã®å®ç¾© * * SDã«ã¼ãã®ç»åãèªã¿è¾¼ãã§ViewPagerã«é ç½®ããImageViewã«è¡¨ç¤ºãã * ImageViewã¸ã®ç»åã®é ç½®ã¯GalleryPagerAdapter(PagerAdapterãç¶æ¿ãããµãã¯ã©ã¹)ã * 使ãã®ã§ç»åãæ ¼ç´ããGalleryPagerAdapterãViewPagerã«ã»ãããã¦ç»åã表示ãã */ private def viewGalleryPager: Unit = { /* ViewPagerã¯ã¤ã³ã¹ã¿ã³ã¹ã®çæã®ä»£ããã«ã¬ã¤ã¢ã¦ãXMLã«è¨è¿°ããæ¹æ³ã§ãè¯ã */ val galleryPager = new ViewPager(PictureViewerActivity.this) val galleryPagerAdapter = new GalleryPagerAdapter(PictureViewerActivity.this) /* SDã«ã¼ãã®ç»åãã¼ã¿ã®URIã«åãåããããã¦æ¤ç´¢çµæãCursorã«æ ¼ç´ãã */ val imageMediaStoreUri: Uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI val mediaContentResolver: ContentResolver = getContentResolver val pictureCursor: Cursor = mediaContentResolver.query(imageMediaStoreUri, null, null, null, null) /* Cursorã«æ ¼ç´ããç»åãã¼ã¿ã®æ¤ç´¢çµæã®å é ããé ã«ç»åãåå¾ãGalleryPagerAdapterã«æ ¼ç´ãã */ pictureCursor.moveToFirst do { /* ç»åãã¼ã¿ã®URIã¨IDããç»å(ããããããç»å)ãåå¾ãã */ val pictureId = pictureCursor.getLong(pictureCursor.getColumnIndex(BaseColumns._ID)).asInstanceOf[Int] val bmpImageUri: Uri = ContentUris.withAppendedId(imageMediaStoreUri, pictureId) val bmpImage: Bitmap = MediaStore.Images.Media.getBitmap(mediaContentResolver, bmpImageUri) galleryPagerAdapter.addPicture(bmpImage) } while (pictureCursor.moveToNext) /* ç»åãé ç½®ããViewPagerãã¬ã¤ã¢ã¦ãã«è¨ç½®ãã¦ç»é¢ã«ç»åã表示ãã */ galleryPager.setAdapter(galleryPagerAdapter) setContentView(galleryPager) } /** * openSettingsã¡ã½ããã®å®ç¾© * * ã¤ã³ãã³ãã使ã£ã¦ã¢ããªã®è¨å®ç»é¢ãéã */ private def openSettings: Unit = { val appSettingsIntent: Intent = new Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) val appPackageUri: Uri = Uri.fromParts("package", getPackageName, null) /* ã¤ã³ãã³ãã«ã¢ããªã®URIãæå®ãã¦ã¢ããªæ å ±ã®ç»é¢ãéã */ appSettingsIntent.setData(appPackageUri) startActivity(appSettingsIntent) } /** * requestReadStoragePermissionã¡ã½ããã®å®ç¾© * * READ_EXTERNAL_STORAGEã®ãã¼ããã·ã§ã³ã®è¨±å¯(権éåå¾)ãè¦æ±ãã * shouldShowRequestPermissionRationaleã¡ã½ããã使ã£ã¦ * 以åã«ãã¼ããã·ã§ã³ã®è¨±å¯ãæå¦ããããã¨ãããã確èªã * æå¦ããããã¨ãããå ´åã¯ãã¼ããã·ã§ã³ã®è¨±å¯ãå¿ è¦ãªçç±ã * ãã¤ã¢ãã°ã«è¡¨ç¤ºãã¦ãããã¼ããã·ã§ã³ã®è¨±å¯ãè¦æ±ãã */ private def requestReadStoragePermission: Unit = { /* ãã¼ããã·ã§ã³ã®è¨±å¯ãæå¦ããããã¨ãããã確èªãã */ if (ActivityCompat.shouldShowRequestPermissionRationale(PictureViewerActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)) { /* ãã¼ããã·ã§ã³ã®è¨±å¯ãæå¦ããããã¨ãããã°è¨±å¯ãå¿ è¦ãªçç±ã説æãã¦ãã許å¯ãè¦æ±ãã */ new AlertDialog.Builder(PictureViewerActivity.this) .setTitle("ãã¼ããã·ã§ã³ã®è¿½å 説æ") .setMessage("ãã®ã¢ããªã§ç»åã表示ããã«ã¯ãã¼ããã·ã§ã³ãå¿ è¦ã§ã") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener { override def onClick(dialogInterface: DialogInterface, i: Int): Unit = { /* ãã¼ããã·ã§ã³ã®è¨±å¯ãè¦æ± */ ActivityCompat.requestPermissions( PictureViewerActivity.this, Array[String](Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_READ_STORAGE_PERMISSION_CODE ) } }) .create .show } else { /* ååè¦æ±æããä»å¾ã¯ç¢ºèªããªãããé¸æããã¦ããå ´åã®ãã¼ããã·ã§ã³ã®è¨±å¯ã®è¦æ± */ ActivityCompat.requestPermissions( PictureViewerActivity.this, Array[String](Manifest.permission.READ_EXTERNAL_STORAGE), REQUEST_READ_STORAGE_PERMISSION_CODE ) } } /** * onRequestPermissionsResultã¡ã½ããããªã¼ãã¼ã©ã¤ã * * ãã®ã¡ã½ããã¯requestPermissionsã¡ã½ããã®ã³ã¼ã«ããã¯ã¡ã½ãã㧠* requestPermissionsã¡ã½ããã§ãã¼ããã·ã§ã³ã®è¨±å¯ãè¦æ±ããçµæãåå¾ãã * å¼æ°ã®requestCodeã§è¦æ±ããããã¼ããã·ã§ã³ãåºå¥ã * grantResultã®è¦ç´ ã§ãã¼ããã·ã§ã³ã®è¨±å¯ã»ä¸è¨±å¯ã確èªãã */ override def onRequestPermissionsResult(requestCode: Int, permissions: Array[_root_.java.lang.String], grantResults: Array[Int]): Unit = { /* è¦æ±ããããã¼ããã·ã§ã³ã«ãã£ã¦å¯¾å¿ãå¤ããã®ã§ä½ã®ãã¼ããã·ã§ã³ã確èªãã */ requestCode match { case REQUEST_READ_STORAGE_PERMISSION_CODE â /* ãã¼ããã·ã§ã³ã®è¦æ±ãæå¦ããã¦ããå ´åã¯ãã¤ã¢ãã°ã«è¡¨ç¤ºãã */ if (grantResults.length != 1 || grantResults(0) != PackageManager.PERMISSION_GRANTED) { /* ãä»å¾ã¯ç¢ºèªããªãããé¸æããã¦ããªããã°å度ãã¼ããã·ã§ã³ã®è¨±å¯ãè¦æ±ãã */ if (ActivityCompat.shouldShowRequestPermissionRationale(PictureViewerActivity.this, Manifest.permission.READ_EXTERNAL_STORAGE)) { new AlertDialog.Builder(PictureViewerActivity.this) .setTitle("ãã¼ããã·ã§ã³åå¾ã¨ã©ã¼") .setMessage("ç»åã®è¡¨ç¤ºã«å¿ è¦ãªãã¼ããã·ã§ã³ãåå¾ã§ãã¾ããã§ãã") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener { override def onClick(dialogInterface: DialogInterface, i: Int): Unit = { requestReadStoragePermission } }) .create .show } else { /* ãä»å¾ã¯ç¢ºèªããªãããé¸æããã¦ããå ´åã¯ã¢ããªã®è¨å®ç»é¢ãéã */ new AlertDialog.Builder(PictureViewerActivity.this) .setTitle("ãã¼ããã·ã§ã³åå¾ã¨ã©ã¼") .setMessage("ä»å¾ã¯è¨±å¯ããªããé¸æããã¾ããï¼ï¼ã¢ããªè¨å®ï¼æ¨©éã確èªãã¦ãã ããï¼æ¨©éãON/OFFãããã¨ã§ç¶æ ã¯ãªã»ããããã¾ãï¼") .setPositiveButton(android.R.string.ok, new DialogInterface.OnClickListener { override def onClick(dialogInterface: DialogInterface, i: Int): Unit = { /* ã¢ããªã®è¨å®ç»é¢ãéãã¦æåã§è¨±å¯ãã¦ããã */ openSettings } }) .create .show } } else { /* ãã¼ããã·ã§ã³ã許å¯ãããå ´åã¯ç»åã表示ãã */ viewGalleryPager } } } }
GalleryPagerAdapter.scala
package com.b0npu.picturegallery import android.content.Context import android.graphics.Bitmap import android.support.v4.view.PagerAdapter import android.view.{View, ViewGroup} import android.widget.ImageView /** * ç»åãViewPagerã«è¡¨ç¤ºããããã®Adapterã¯ã©ã¹(PagerAdapterã®ãµãã¯ã©ã¹) * * ViewPagerã表示ããActivityã®æ å ±(Context)ãå¼æ°ã§ååãViewPagerã®Pageãçæãã * ViewPagerã®Pageã«ã¯ImageViewãé ç½®ãaddPictureã¡ã½ããã§ååã£ãç»åã表示ãã */ class GalleryPagerAdapter(context: Context) extends PagerAdapter { /** * ãã£ã¼ã«ãã®å®ç¾© * * ã³ã³ã¹ãã©ã¯ã¿ã®å¼æ°(Context)ãæ ¼ç´ããå®æ°ãå®ç¾© * addPictureã¡ã½ããã§ååã£ãç»å(ããããããç»å)ãæ ¼ç´ããé åãå®ç¾© * (èªã¯ã©ã¹ã§ä½¿ãã ãã®ãã£ã¼ã«ãã¯privateã«ãã¦æ示çã«éå ¬éã«ãã¦ã¾ã) */ private val galleryContext: Context = context private var galleryArray: Array[Bitmap] = Array.empty /** * addPictureã¡ã½ããã®å®ç¾© * * å¼æ°ã«ç»å(ããããããç»å)ãååãé åã«æ ¼ç´ãã * TODO: ç»åãç´æ¥é åã«æ ¼ç´ãã¦ããã®ã§ç»åã®ææ°ãå¤ããªãã¨éããªãã¾ã */ def addPicture(bitmap: Bitmap): Unit = { galleryArray :+= bitmap } /** * instantiateItemã¡ã½ããããªã¼ãã¼ã©ã¤ã * * ãã®ã¡ã½ããã¯ViewPagerã«Pageã追å ããã¡ã½ãã㧠* å¼æ°ã®container(ViewGroup)ã®positionã®å ´æã«Viewã表示ãã * containerã«è¿½å ããImageViewã«addPictureã¡ã½ãã㧠* galleryArrayã«æ ¼ç´ããç»å(ããããããç»å)ãé ç½®ã㦠* ViewPagerã«ç»åã表示ãã */ override def instantiateItem(container: ViewGroup, position: Int): AnyRef = { val bitmapPicture: Bitmap = galleryArray(position) val imageView: ImageView = new ImageView(galleryContext) container.addView(imageView) imageView.setImageBitmap(bitmapPicture) imageView } /** * destroyItemã¡ã½ããããªã¼ãã¼ã©ã¤ã * * ãã®ã¡ã½ããã¯ViewPagerããPageãåé¤ããã¡ã½ãã㧠* å¼æ°ã®container(ViewGroup)ã®positionã®å ´æã«ããobj(Viewçã®Object)ãåé¤ãã */ override def destroyItem(container: ViewGroup, position: Int, obj: Object): Unit = { container.removeView(obj.asInstanceOf[View]) } /** * getCountã¡ã½ããããªã¼ãã¼ã©ã¤ã * * ãã®ã¡ã½ããã¯ViewPagerã«è¿½å ããViewã®æ°ãåå¾ãã * galleryArrayã«æ ¼ç´ããç»å(SDã«ã¼ãã«ä¿åããã¦ããå ¨ç»å)ã®æ°ãåå¾ãã */ override def getCount: Int = { galleryArray.length } /** * isViewFromObjectã¡ã½ããããªã¼ãã¼ã©ã¤ã * * ãã®ã¡ã½ããã¯ViewPagerã®Pageã«Viewãããã確èªããã¡ã½ãã㧠* instantiateItemã¡ã½ããã§è¿½å ãããItem(Object)ãViewã§ããã°Trueã«ãªã */ override def isViewFromObject(view: View, obj: Object): Boolean = { view == obj } }
activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" android:paddingBottom="@dimen/activity_vertical_margin" tools:context="com.b0npu.picturegallery.PictureViewerActivity"> </RelativeLayout>
res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">PictureGallery</string> </resources>
build.sbt
ã»
ã»
ã»
name := "PictureGallery"
ã»
ã»
ã»
Run/Debugã®å®è¡çµæ
ãã¾ãããã°ãç»åã表示ããã¦å°ãå¬ããæ°æã¡ã«ãªãã¾ãã
åèè¨äº
ScalaãAndroidã«é¢ãã¦ã¯ããã¡ãã®è¨äºãåèã«ããã¦ããã ãã¾ããã
- Scalacheat - Scala Documentation
- ViewPager | Android Developers
- PagerAdapter | Android Developers
- MediaStore.Images.ImageColumns | Android Developers
- BaseColumns | Android Developers
ã®ã£ã©ãªã¼ã¢ããªã®ä½æã«é¢ãã¦ã¯ããã¡ãã®è¨äºãåèã«ããã¦ããã ãã¾ããã
- Android Tips #30 ViewPager を使ってスワイプで View を切り替える | Developers.IO
- ContentProviderで端末内画像データを取得する « Tech Booster
éçºç°å¢
- OSX 10.11.6 El Capitan
- IDEï¼ InteiijJ IDEA Community Edition 2016.2
- Java Development Kitï¼ Java SE Development Kit 8u101
- Android SDK Toolsï¼ android-sdk_r24.4.1-macosx
- Android Virtual Deviceï¼ Android 6.0(Google APIs) API level 23 - Scala 2.11.8
- ãã«ããã¼ã«ï¼ sbt 0.13.12