前回に引き続き、Flutterの勉強として電卓アプリ(計算機)を作ったので、その作り方を順を追って、全3回で説明していきます。
-
1
-
2
-
計算機能の実装3
今回は「計算機能の実装」を行います。
では始めていきましょう。
Calculatorクラスの作成
calculation.dartを新規作成
計算を行うクラスとして Calculatorクラス を作成します。
前回までと同様main.dartに書くと、コードが長くなり、ゴチャゴチャしそうです。
なので、calculation.dartというファイルを作成し、そこにCalculatorクラスを作ることにします。
以下のGIFのように新しいファイルを作成します。
calculation.dartを次のようにします。
numberは数字、opは演算子のリスト(可変長配列)です。
class Calculator{
var number = new List();
var op = new List();
static void GetKey(String letter){
// TODO キー入力 -> 配列に格納
}
static String Execute(){
int result;
// TODO 計算処理
return result.toString();
}
}
main.dartとの連携
まず、main.dartにcalculation.dartをimportします。
import 'dart:async';
import 'package:flutter/material.dart';
import 'calculation.dart'; //追加
続いて、_TextFiledStateの内容を変更します。
_expressionの初期値がレイアウト作成の時のままの'1+1'となっていたので '' に直しておきます。
また、_UpdateText()のif文分岐内容も変更します。
// 〜〜〜省略〜〜〜
// 表示
class TextField extends StatefulWidget {
_TextFiledState createState() => _TextFiledState();
}
class _TextFiledState extends State<TextField> {
String _expression = '';
void _UpdateText(String letter){
setState(() {
if(letter == 'C')
_expression = '';
else if (letter == '='){
_expression='';
var ans = Calculator.Execute();
controller.sink.add(ans);
}else if (letter == 'e'){
_expression = 'Error';
}
else
_expression += letter;
});
}
@override
Widget build(BuildContext context) {
// 〜〜〜省略〜〜〜
最後に_TextFiledStateのinitState()の内容を変更します。
まず、controllerのインスタンス化のところ、最後にbroadcast()を追加します。
そして、controllerにCalculator.GetKey()を追加で登録します。
static final controller = StreamController.broadcast();
@override
void initState() {
controller.stream.listen((event) => _UpdateText(event));
controller.stream.listen((event) => Calculator.GetKey(event));
}
Calculatorのメソッド
GetKey()メソッドの作成
次のような処理を行うメソッドを作ろうと思います。
例.)
入力 : 10+25×3-1
->
number:[10, 25, 3, 1]
op:[+, ×, -]
このメソッドは
・数字
・四則演算子
・C
・=
のボタンが押された時に呼び出されます。
なのでそれぞれ場合分けして処理をします。
const c_op = ['+', '-', '×', '÷'];
class Calculator{
static var _number = new List();
static var _op = new List();
static String _buffer;
static void GetKey(String letter){
// 四則演算子
if(c_op.contains(letter)){
_op.add(letter);
_number.add(double.parse(_buffer));
_buffer = '';
} // C
else if(letter == 'C'){
_number.clear();
_op.clear();
_buffer = '';
} // =
else if(letter == '='){
return null;
}// 数字
else{
_buffer += letter;
}
}
// 〜〜〜省略〜〜〜
各メソッドの説明
double.parse()を使用して、文字列をdoubleに解析できます
it-swarm.dev
contains(Object element) → bool
List class(公式)
Returns true if the collection contains an element equal to element. [...]
add(E value) → void
List class(公式)
Adds value to the end of this list, extending the length by one. [...]
clear() → void
List class(公式)
Removes all objects from this list; the length of the list becomes zero. [...]
Execute()メソッドの作成
計算処理を書いていきます。
今回は四則演算の順序を守らず、ー符号の入力もできない物を作ります。
(ただ面倒だっただけです。ごめんなさい。)
// 〜〜〜省略〜〜〜
static double _result;
static String Execute() {
_number.add(double.parse(_buffer));
if (_number.length == 0)
return '0';
_result = _number[0];
for (int i = 0; i < _op.length; i++) {
if (_op[i] == '+')
_result += _number[i + 1];
else if (_op[i] == '-')
_result -= _number[i + 1];
else if (_op[i] == '×')
_result *= _number[i + 1];
else if (_op[i] == '÷' && _number[i + 1] != 0)
_result /= _number[i + 1];
else
return 'e';
}
_number.clear();
_op.clear();
_buffer = '';
var resultStr = _result.toString().split('.');
return resultStr[1] == '0' ? resultStr[0] : _result.toString();
}
}
最後の2行
var resultStr = _result.toString().split('.');
return resultStr[1] == '0' ? resultStr[0] : _result.toString();
doubleをtoString()すると、2.0などと小数点以下0の文字列が返ってしまうので、それを直す処理を書いています。
完成
(プログラム全体はこのページの最後に載せてます。)
色々雑だったけど、ひとまず完成しました!
電卓できた#Flutter pic.twitter.com/hPwRsER0wD
— 2357 (@95s7k84695a) May 31, 2020
実機で動かしてみる(iOS)
現在開いているシュミレーターを終了し、接続した実機を選択
AndroidStudioの下のタブの「ターミナル」をクリックして統合シェルを起動して次のコマンドを入力します。
fluter install
Installing com.example.calculatorapp to 〜〜〜のiPhone7... Could not find application bundle at build/ios/iphoneos/Runner.app; have you run "flutter build ios"? Install failed
返ってきたので、書かれている通りに
flutter build ios
と入力します。
Building com.example.calculatorapp for device (ios-release)... ════════════════════════════════════════════════════════════════════════════════ No valid code signing certificates were found You can connect to your Apple Developer account by signing in with your Apple ID in Xcode and create an iOS Development Certificate as well as a Provisioning Profile for your project by: 1- Open the Flutter project's Xcode target with open ios/Runner.xcworkspace 2- Select the 'Runner' project in the navigator then the 'Runner' target in the project settings 3- Make sure a 'Development Team' is selected. - For Xcode 10, look under General > Signing > Team. - For Xcode 11 and newer, look under Signing & Capabilities > Team. You may need to: - Log in with your Apple ID in Xcode first - Ensure you have a valid unique Bundle ID - Register your device with your Apple Developer Account - Let Xcode automatically provision a profile for your app 4- Build or run your project again 5- Trust your newly created Development Certificate on your iOS device via Settings > General > Device Management > [your new certificate] > Trust For more information, please visit: https://developer.apple.com/library/content/documentation/IDEs/Conceptual/ AppDistributionGuide/MaintainingCertificates/MaintainingCertificates.html Or run on an iOS simulator without code signing ════════════════════════════════════════════════════════════════════════════════ No development certificates available to code sign app for device deployment
と返ってきた。。。
1つずつ順にやっていきます。
1-
1- Open the Flutter project's Xcode target with open ios/Runner.xcworkspace
AndroidStudioの統合シェルに
open ios/Runner.xcworkspace
と入力すると、Xcodeか開きます。
2-
2- Select the 'Runner' project in the navigator then the 'Runner' target in the project settings
先ほど開いたXcodeで作業をします。
Runnerをクリックして、チームを選択します。
チームをちゃんと選択するにはもう少し作業が必要なようなので、1つずつ確認して作業していきます。
3-
3- Make sure a 'Development Team' is selected. - For Xcode 10, look under General > Signing > Team. - For Xcode 11 and newer, look under Signing & Capabilities > Team. You may need to: - Log in with your Apple ID in Xcode first - Ensure you have a valid unique Bundle ID - Register your device with your Apple Developer Account - Let Xcode automatically provision a profile for your app
- Log in with your Apple ID in Xcode first
ログインしてある。
- Ensure you have a valid unique Bundle ID
この警告と同じこといってるのかな?と思うので、
こんな感じに変更しました。
- Register your device with your Apple Developer Account
これかな?
Preference... > Accounts
- Let Xcode automatically provision a profile for your app
よくわからない。。無視。
4-
4- Build or run your project again
ではもう一回
flutter build ios
すると、パスワード求められるから答える。
「許可」でもいいんだけど、何回も問われて面倒だから「常に許可」に。
終わったら、
flutter install
を入力。
iPhoneにアプリが入った。
開こうとするとこうなる。
Untrusted だと。
5-
5- Trust your newly created Development Certificate on your iOS device via Settings > General > Device Management > [your new certificate] > Trust
書いてある通り、実機の
「設定」>「一般」>「プロファイルとデバイス管理」より「信頼」っと。
実機で動かすことができました。
以上でFlutter電卓作成は終了です。
参考
プログラム全体
[main.dart]
import 'dart:async';
import 'package:flutter/material.dart';
import 'calculation.dart';
void main() => runApp(MyApp());
class MyApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MaterialApp(
home: Scaffold(
body: Column(
mainAxisAlignment: MainAxisAlignment.start,
children: [
TextField(),
Keyboard(),
],
)
)
);
}
}
//==============================================================================
// 表示
class TextField extends StatefulWidget {
_TextFiledState createState() => _TextFiledState();
}
class _TextFiledState extends State<TextField> {
String _expression = '';
void _UpdateText(String letter){
setState(() {
if(letter == 'C')
_expression = '';
else if (letter == '='){
_expression='';
var ans = Calculator.Execute();
controller.sink.add(ans);
}else if (letter == 'e'){
_expression = 'Error';
}
else
_expression += letter;
});
}
@override
Widget build(BuildContext context) {
return Expanded(
flex: 1,
child: Container(
child: Align(
alignment: Alignment.centerRight,
child: Text(
_expression,
style: TextStyle(
fontSize: 64.0,
),
),
),
)
);
}
static final controller = StreamController<String>.broadcast();
@override
void initState() {
controller.stream.listen((event) => _UpdateText(event));
controller.stream.listen((event) => Calculator.GetKey(event));
}
}
//==============================================================================
// キーボード
class Keyboard extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Expanded(
flex: 2,
child: Center(
child: Container(
color: const Color(0xff87cefa),
child: GridView.count(
crossAxisCount: 4,
mainAxisSpacing: 3.0,
crossAxisSpacing: 3.0,
children: [
'7', '8', '9', '÷',
'4', '5', '6', '×',
'1', '2', '3', '-',
'C', '0', '=', '+',
].map((key) {
return GridTile(
child: Button(key),
);
}).toList(),
),
)
)
);
}
}
// キーボタン
class Button extends StatelessWidget {
final _key;
Button(this._key);
@override
Widget build(BuildContext context) {
return Container(
child: FlatButton(
child: Center(
child: Text(
_key,
style: TextStyle(
fontSize: 46.0,
color: Colors.black54,
),
),
),
onPressed: (){
_TextFiledState.controller.sink.add(_key);
},
)
);
}
}
[calculation.dart]
const c_op = ['+', '-', '×', '÷'];
class Calculator{
static var _number = new List();
static var _op = new List();
static String _buffer;
static void GetKey(String letter){
// 四則演算子
if(c_op.contains(letter)){
_op.add(letter);
_number.add(double.parse(_buffer));
_buffer = '';
} // C
else if(letter == 'C'){
_number.clear();
_op.clear();
_buffer = '';
} // =
else if(letter == '='){
return null;
}// 数字
else{
_buffer += letter;
}
}
static double _result;
static String Execute() {
_number.add(double.parse(_buffer));
if (_number.length == 0)
return '0';
_result = _number[0];
for (int i = 0; i < _op.length; i++) {
if (_op[i] == '+')
_result += _number[i + 1];
else if (_op[i] == '-')
_result -= _number[i + 1];
else if (_op[i] == '×')
_result *= _number[i + 1];
else if (_op[i] == '÷' && _number[i + 1] != 0)
_result /= _number[i + 1];
else
return 'e';
}
_number.clear();
_op.clear();
_buffer = '';
var resultStr = _result.toString().split('.');
return resultStr[1] == '0' ? resultStr[0] : _result.toString();
}
}
0 件のコメント:
コメントを投稿