文字通り前の記事で、投票の過半数により、JavaでAndroid用に作成されたネイティブアプリケーションの類似物を作成する一連のレッスンを開始することが決定されましたが、Kivy + Pythonフレームワークを使用しました。 それは考慮されます:コントロールとウィジェットの作成とレイアウト、Kv-Languageでのユーザーインターフェイスレイアウト手法の詳細な調査、画面要素の動的制御、Androidマテリアルデザインへのアクセスを提供するライブラリなど
興味を持って、カットしてください!
したがって、Javaを話すことに同意したローマのHvashchevsky habrovchaninのアドバイスに基づいて、適切なアプリケーションの実験ウサギの失敗した検索の後、適度に複雑(チュートリアルをサンタバーバラの規模に拡張しないように)および単純ではありません(可能な限りKivy開発の技術的側面をカバーするため)。私たちのレッスンのコンサルタント(Javaで書かれたオリジナルのコードのリストを掲載する記事で時々)、私はここにリダイレクトされました -そして選択が行われました:
会話は、XMPP / Jabberプロトコルを使用したAndroid用のインスタントメッセンジャーアプリケーションです。 WhatsApp、WeChat、Line、Facebook Messenger、Google Hangouts、Threemaなどのプログラムの代替。
|
このアプリケーションに基づいてレッスンが構築され、最終記事の終わりまでにリリースに近づくと、 Python、ヒキガエル、フルーツの爬虫類の水陸両用果実トンドがありますJabber-Python-Kivy-PyConversationsおよびPython3でコンパイルされた切望されたapk-chechka!
私たちが始めているので、あなたがお茶とタバコを買いだめしたことを望みます! いつものように、まだ取得していない場合は、Kivyアプリケーション用の新しいプロジェクトを作成するためのウィザードが必要になります。 ラボでクローンを作成し、ターミナルでウィザードのルートディレクトリを開き、コマンドを実行します。
python3 main.py PyConversations ///// -repo https://github.com/User/PyConversations -autor Easy -mail gorodage@gmail.com
当然のことながら、Kivyフレームワーク自体は、そのインストールをここで読むことができます 。 もちろん、新しいプロジェクトウィザードのリポジトリ内のリンクを使用して、Androidマテリアルデザインのスタイルでネイティブインターフェイスを作成するための素晴らしいKivyMDライブラリを既に見つけました。
PornHubの githubに移動して、PyConversations担当者をフォーク/クローン/ダウンロードします。あなたと私が始めたプロジェクトは小さくなく、新しい記事が出てくると、新しい関数、クラス、およびファイルとともに成長します。 それ以外の場合、すでに2番目の記事で、 竹を吸って 、なぜ何も効果がないのか疑問に思うでしょう。
そのため、プロジェクトが作成されます。
今日の記事では、公式の会話アプリケーションの最初の4つのアクティビティ(新しいアカウントを登録するアクティビティ)を取り上げました。
しかし、始める前に、お互いを理解するために、基本的なルールと概念を理解する必要があります...
動的クラスの作成と管理
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import StringProperty Builder.load_string(''' #: import MDFlatButton kivymd.button.MDFlatButton # Kivy-Language python : # from kivymd.button import MDFlatButton # # kv- , # , , : #: include your_kv_file.kv # # , Kivy , # Activity — . # Activity BoxLayout - # , . <StartScreen> MDFlatButton: id: button text: 'Press Me' size_hint_x: 1 # - 0 1 pos_hint: {'y': .5} # 'y' # . on_release: # 'root' - , # . root.set_text_on_button() ''') # Builder.load_file('path/to/kv-file'), # Activity . class StartScreen(BoxLayout): ''' .''' new_text_for_button = StringProperty() # Kivy : # # StringProperty; # NumericProperty; # BoundedNumericProperty; # ObjectProperty; # DictProperty; # ListProperty; # OptionProperty; # AliasProperty; # BooleanProperty; # ReferenceListProperty; # # # . # # , : # # new_text_for_button = '' # # - # TypeError: object.__init__() takes no parameters. def set_text_on_button(self): self.ids.button.text = self.new_text_for_button # ids - Activity # . # # , 'button' - self.ids.button - # , # . # , Properties, # 'on_', # . def on_new_text_for_button(self, instance, value): print(instance, value) class Program(App): def build(self): ''', . Activity.''' return StartScreen(new_text_for_button='This new text') if __name__ in ('__main__', '__android__'): Program().run() #
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import StringProperty Builder.load_string(''' #: import MDFlatButton kivymd.button.MDFlatButton <StartScreen> MDFlatButton: id: button text: 'Press Me' size_hint_x: 1 pos_hint: {'y': .5} on_release: # 'self' # . self.text = root.new_text_for_button ''') class StartScreen(BoxLayout): new_text_for_button = StringProperty() def on_new_text_for_button(self, instance, value): print(instance, value) class Program(App): def build(self): return StartScreen(new_text_for_button='This new text') if __name__ in ('__main__', '__android__'): Program().run()
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import StringProperty Builder.load_string(''' #: import MDFlatButton kivymd.button.MDFlatButton <StartScreen> orientation: 'vertical' MDFlatButton: id: button text: 'Press Me' size_hint: 1, 1 pos_hint: {'center_y': .5} on_release: # id . # , Python # , Python . button_two.text = 'Id: "button_two: " {}'.format(root.new_text_for_button) MDFlatButton: id: button_two text: 'Id: "button_two: " Old text' size_hint: 1, 1 pos_hint: {'center_y': .5} ''') class StartScreen(BoxLayout): new_text_for_button = StringProperty() class Program(App): def build(self): return StartScreen(new_text_for_button='This new text') if __name__ in ('__main__', '__android__'): Program().run()
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import StringProperty Builder.load_string(''' #: import MDFlatButton kivymd.button.MDFlatButton #: import snackbar kivymd.snackbar <StartScreen> orientation: 'vertical' MDFlatButton: id: button text: 'Press Me' size_hint: 1, 1 pos_hint: {'center_y': .5} on_release: button_two.text = 'Id: "button_two: " {}'.format(root.new_text_for_button) MDFlatButton: id: button_two text: 'Id: "button_two: " Old text' size_hint: 1, 1 pos_hint: {'center_y': .5} on_text: # 'text'. snackbar.make(', ! !') ''') class StartScreen(BoxLayout): new_text_for_button = StringProperty() class Program(App): def build(self): return StartScreen(new_text_for_button='This new text') if __name__ in ('__main__', '__android__'): Program().run()
from kivy.app import App from kivy.uix.boxlayout import BoxLayout from kivy.lang import Builder from kivy.properties import StringProperty Builder.load_string(''' #: import MDFlatButton kivymd.button.MDFlatButton <StartScreen> MDFlatButton: # 'app' — - # , # , # kivy.app.App. text: app.string_attribute size_hint_x: 1 pos_hint: {'y': .5} ''') class StartScreen(BoxLayout): pass class Program(App): string_attribute = StringProperty('String from App') def build(self): return StartScreen() if __name__ in ('__main__', '__android__'): Program().run()
from kivy.app import App from kivy.lang import Builder Activity = ''' <MyScreen@FloatLayout>: Label: text: 'Text 1' BoxLayout: MyScreen: ''' class Program(App): def build(self): return Builder.load_string(Activity) if __name__ in ('__main__', '__android__'): Program().run()
from kivy.app import App from kivy.lang import Builder Activity = ''' #: import MDFlatButton kivymd.button.MDFlatButton # , , # , . - FloatLayout. <MyScreen@FloatLayout>: Label: id: label_1 text: 'Text 1' BoxLayout: orientation: 'vertical' MyScreen: id: my_screen MDFlatButton: text: 'Press me' size_hint_x: 1 on_press: my_screen.ids.label_1.text = 'New text' ''' class Program(App): def build(self): return Builder.load_string(Activity) if __name__ in ('__main__', '__android__'): Program().run()
後で説明する内容を理解するために、今のところこれで十分です。途中でトレンチの残りの部分について説明します。 それでは、プロジェクトの開始アクティビティから始めましょう。 start_screen.kvファイルを開きます。 プロジェクトツリーでは、他のすべてのアクティビティアプリケーションと同様に、 libs / uix / kv / activityディレクトリにあります。
アクティビティは次のようになります。
#: kivy 1.9.1 #: import Toolbar kivymd.toolbar.Toolbar #: import NoTransition kivy.uix.screenmanager.NoTransition <StartScreen>: orientation: 'vertical' Toolbar: id: action_bar background_color: app.theme_cls.primary_color # title: app.title opposite_colors: True # elevation: 10 # # - # left_action_items: [['name-icon', function], …] # - # right_action_items: [['name-icon', function], …] ScreenManager: id: root_manager transition: NoTransition() # Activity Introduction: id: introduction # Activity . on_enter: self._on_enter(action_bar, app) CreateAccount: id: create_account on_enter: self._on_enter(action_bar, app, root_manager) AddAccount: id: add_account on_enter: self._on_enter(action_bar, app) # Activity. on_leave: action_bar.title = app.data.string_lang_create_account AddAccountOwn: id: add_account_own_provider on_enter: self._on_enter(action_bar, app, root_manager) on_leave: action_bar.title = app.title; action_bar.left_action_items = []
しかし、より明確に:
次に、パスlibs / uix / kv / activity / baseclassにある基本クラスActivity StartScreenを開きます。
startscreen.py:
from kivy.uix.boxlayout import BoxLayout class StartScreen(BoxLayout): pass
ご覧のとおり、クラスは空ですが、BoxLayoutコンテナから継承されます。BoxLayoutコンテナは、 'orientation'-'vertical'または 'horizontal'パラメーター(デフォルトでは 'horizontal')に応じて、ウィジェットを垂直または水平に配置します。 アクティビティStartScreenのさらに詳細な図を次に示します。
アクティビティStartScreenの基本クラスは、BoxLayoutからマークアップ自体を継承し、その方向を従来とは異なる垂直方向として宣言し、ToolBarとScreenManagerをコンテナに配置しました。 ScreenManagerは、作成されたアクティビティを含む画面画面を配置し、後で名前を付けるだけで画面にインストールする一種のコンテナです。 例:
from kivy.app import App from kivy.lang import Builder Activity = ''' #: import MDFlatButton kivymd.button.MDFlatButton ScreenManager: Screen: name: 'Screen one' # MDFlatButton: text: 'I`m Screen one with Button' size_hint: 1, 1 on_release: root.current = 'Screen two' # Screen: name: 'Screen two' BoxLayout: orientation: 'vertical' Image: source: 'data/logo/kivy-icon-128.png' MDFlatButton: text: 'I`m Screen two with Button' size_hint: 1, 1 on_release: root.current = 'Screen one' ''' class Program(App): def build(self): return Builder.load_string(Activity) if __name__ in ('__main__', '__android__'): Program().run()
ScreenManagerには、アクティビティのある4つの画面(Introduction、CreateAccount、AddAccount、AddAccountOwn)が含まれています。 最初のものから始めましょう:
#: kivy 1.9.1 #: import MDFlatButton kivymd.button.MDFlatButton # Activity . <Introduction>: name: 'Start screen' BoxLayout: orientation: 'vertical' padding: dp(5), dp(20) Image: source: 'data/images/logo.png' size_hint: None, None size: dp(150), dp(150) pos_hint: {'center_x': .5} Label: text: app.data.string_lang_introduction markup: True color: app.data.text_color text_size: dp(self.size[0] - 10), self.size[1] size_hint_y: None valign: 'top' height: dp(250) Widget: BoxLayout: MDFlatButton: text: app.data.string_lang_create_account on_release: app.screen_root_manager.current = 'Create account' MDFlatButton: text: app.data.string_lang_own_provider theme_text_color: 'Primary' on_release: app.delete_textfield_and_set_check_in_addaccountroot () app.screen_root_manager.current = 'Add account own provider'
以下は、このアクティビティがデバイス画面に表示するものです(私は自分自身にいくつかの自由を許しましたが、それはより良いように思えました):
Javaのオリジナルは次のとおりです。
<?xml version="1.0" encoding="utf-8"?> <ScrollView xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:fillViewport="true"> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:background="?attr/color_background_primary"> <LinearLayout android:id="@+id/linearLayout" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:minHeight="256dp" android:orientation="vertical" android:paddingBottom="10dp" android:paddingLeft="16dp" android:paddingRight="16dp"> <Space android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/welcome_header" android:textColor="?attr/color_text_primary" android:textSize="?attr/TextSizeHeadline" android:textStyle="bold"/> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="@string/welcome_text" android:textColor="?attr/color_text_primary" android:textSize="?attr/TextSizeBody"/> <Button android:id="@+id/create_account" style="?android:attr/borderlessButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:text="@string/create_account" android:textColor="@color/accent"/> <Button android:id="@+id/use_own_provider" style="?android:attr/borderlessButtonStyle" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="right" android:text="@string/use_own_provider" android:textColor="?attr/color_text_secondary"/> </LinearLayout> <RelativeLayout android:layout_width="match_parent" android:layout_height="match_parent" android:layout_above="@+id/linearLayout" android:layout_alignParentLeft="true" android:layout_alignParentStart="true" android:layout_alignParentTop="true"> <ImageView android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:padding="8dp" android:src="@drawable/main_logo"/> </RelativeLayout> <TextView android:paddingLeft="8dp" android:paddingRight="8dp" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentBottom="true" android:textColor="?attr/color_text_secondary" android:textSize="@dimen/fineprint_size" android:maxLines="1" android:text="@string/free_for_six_month" android:layout_centerHorizontal="true"/> </RelativeLayout> </ScrollView>
以下は、アクティビティ紹介図です。
次に、ウィジェットの属性について説明します。
BoxLayout: … padding: dp(5), dp(20) # — / /
Image: … # , - # 0 1 (.1, .5, .01 . .). # , size_hint # None, . # , : # # size_hint_x: None # width: 250 # # # # size_hint_y: None # height: 50 # # , Activity, . # size_hint (1, 1), # , . size_hint: None, None size: dp(150), dp(150) # 'x' # '' , # pos, , pos: 120, 90. pos_hint: {'center_x': .5}
以下の例を使用して、ウィジェットの相対的な位置とサイズを試すことができます。
from kivy.app import App from kivy.lang import Builder Activity = ''' FloatLayout: Button: text: "We Will" pos: 100, 100 size_hint: .2, .4 Button: text: "Wee Wiill" pos: 280, 200 size_hint: .4, .2 Button: text: "ROCK YOU!!" pos_hint: {'x': .3, 'y': .6} size_hint: .5, .2 ''' class Program(App): def build(self): return Builder.load_string(Activity) if __name__ in ('__main__', '__android__'): Program().run()
属性の詳細:
Label: … # , markdown # as is. # : # [b][/b] # [i][/i] # [u][/u] # [s][/s] # [font=<str>][/font] # [size=<integer>][/size] # [color=#<color>][/color] # [ref=<str>][/ref] # [anchor=<str>] # [sub][/sub] # [sup][/sup] markup: True # , . text_size: dp(self.size[0] - 10), self.size[1] # : # 'bottom', 'middle', 'center' 'top'. valign: 'top'
テキストを囲む領域を使用して、以下の例を試すことができます。
from kivy.app import App from kivy.uix.label import Label class LabelTextSizeTest(App): def build(self): return Label( text=' , \n' * 50, text_size=(250, 300), # line_height=1.5 ) if __name__ == '__main__': LabelTextSizeTest().run()
アクティビティの詳細:
Widget:
Javaの類似物としてコンテキストで使用されます。
<Space android:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"/>
次:
BoxLayout: MDFlatButton: text: app.data.string_lang_create_account # Activity 'Create account'. on_release: app.screen_root_manager.current = 'Create account' MDFlatButton: text: app.data.string_lang_own_provider # # theme_text_color 'Custom' # - text_color: .7, .2, .2, 1 theme_text_color: 'Primary' on_release: # . # , , # , # Activity, . app.delete_textfield_and_set_check_in_addaccountroot() app.screen_root_manager.current = 'Add account own provider'
だから まだもう1つの質問を検討していません。 Activity StartScreenレイアウトに戻ります。
Introduction: id: introduction # Activity . on_enter: self._on_enter(action_bar, app)
つまり、アクティビティが表示されるとすぐに、on_enterイベントコードが実行されます。 Activity基底クラス(ファイルlibs / uix / kv / activity / baseclass / Introduction.py )で_on_enterメソッドが行うことを見てみましょう
from kivy.uix.screenmanager import Screen class Introduction(Screen): def _on_enter(self, instance_toolbar, instance_program): instance_toolbar.left_action_items = [] instance_toolbar.title = instance_program.title
_on_enterメソッドは、左側のツールバーのアイコンを削除し、left_action_itemsの値を空のリストとして設定し、ToolBarの署名をアプリケーションの名前に変更します。
たとえば、元のJavaから制御クラスを提供します。
package eu.siacs.conversations.ui; import android.app.ActionBar; import android.app.Activity; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.view.View; import android.widget.Button; import eu.siacs.conversations.R; public class WelcomeActivity extends Activity { @Override protected void onCreate(final Bundle savedInstanceState) { if (getResources().getBoolean(R.bool.portrait_only)) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } final ActionBar ab = getActionBar(); if (ab != null) { ab.setDisplayShowHomeEnabled(false); ab.setDisplayHomeAsUpEnabled(false); } super.onCreate(savedInstanceState); setContentView(R.layout.welcome); final Button createAccount = (Button) findViewById(R.id.create_account); createAccount.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { Intent intent = new Intent(WelcomeActivity.this, MagicCreateActivity.class); intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION); startActivity(intent); } }); final Button useOwnProvider = (Button) findViewById(R.id.use_own_provider); useOwnProvider.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { startActivity(new Intent(WelcomeActivity.this, EditAccountActivity.class)); } }); } }
だから 私たちはそれを理解しました。 アクティビティと2つの使用可能なボタンがあります。 最初のものから始めましょう:
ボタンをクリックすると、アクティビティCreateAccountが表示されます。
MDFlatButton: text: app.data.string_lang_create_account on_release: app.screen_root_manager.current = 'Create account'
アクティビティCreateAccount(Kivy):
アクティビティCreateAccount(オリジナル):
プロジェクトのアクティビティCreateAccountを開きましょう:
#: kivy 1.9.1 #: import SingleLineTextField kivymd.textfields.SingleLineTextField #: import snackbar kivymd.snackbar # Activity . # 'Create account' Activity. <CreateAccount>: name: 'Create account' BoxLayout: orientation: 'vertical' padding: dp(5), dp(20) Image: source: 'data/images/logo.png' size_hint: None, None size: dp(150), dp(150) pos_hint: {'center_x': .5} Label: text: app.data.string_lang_enter_user_name markup: True color: app.data.text_color text_size: dp(self.size[0] - 10), self.size[1] size_hint_y: None valign: 'top' height: dp(215) Widget: size_hint_y: None height: dp(10) SingleLineTextField: id: username hint_text: 'Username' message: 'username@conversations.im' message_mode: 'persistent' on_text: app.check_len_login_in_textfield(self) Widget: BoxLayout: MDFlatButton: text: app.data.string_lang_next on_release: if username.text == '' or username.text.isspace(): \ snackbar.make(app.data.string_lang_not_valid_username) else: app.screen_root_manager.current = 'Add account'
ここで新しいことはありません。下の図では、まだ説明していないもののみを示します。
ツールバーのタイトルとアイコンは、_on_enterメソッドのCreateAccountアクティビティの基本クラスで設定されます。
from kivy.uix.screenmanager import Screen class CreateAccount(Screen): def _on_enter(self, instance_toolbar, instance_program, instance_screenmanager): instance_toolbar.title = instance_program.data.string_lang_create_account instance_toolbar.left_action_items = [ ['chevron-left', lambda x: instance_program.back_screen( instance_screenmanager.previous())] ]
package eu.siacs.conversations.ui; import android.content.Intent; import android.content.pm.ActivityInfo; import android.os.Bundle; import android.text.Editable; import android.text.TextWatcher; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.TextView; import android.widget.Toast; import java.security.SecureRandom; import eu.siacs.conversations.Config; import eu.siacs.conversations.R; import eu.siacs.conversations.entities.Account; import eu.siacs.conversations.xmpp.jid.InvalidJidException; import eu.siacs.conversations.xmpp.jid.Jid; public class MagicCreateActivity extends XmppActivity implements TextWatcher { private TextView mFullJidDisplay; private EditText mUsername; private SecureRandom mRandom; private static final String CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456780+-/#$!?"; private static final int PW_LENGTH = 10; @Override protected void refreshUiReal() { } @Override void onBackendConnected() { } @Override protected void onCreate(final Bundle savedInstanceState) { if (getResources().getBoolean(R.bool.portrait_only)) { setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); } super.onCreate(savedInstanceState); setContentView(R.layout.magic_create); mFullJidDisplay = (TextView) findViewById(R.id.full_jid); mUsername = (EditText) findViewById(R.id.username); mRandom = new SecureRandom(); Button next = (Button) findViewById(R.id.create_account); next.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { String username = mUsername.getText().toString(); if (username.contains("@") || username.length() < 3) { mUsername.setError(getString(R.string.invalid_username)); mUsername.requestFocus(); } else { mUsername.setError(null); try { Jid jid = Jid.fromParts(username.toLowerCase(), Config.MAGIC_CREATE_DOMAIN, null); Account account = xmppConnectionService.findAccountByJid(jid); if (account == null) { account = new Account(jid, createPassword()); account.setOption(Account.OPTION_REGISTER, true); account.setOption(Account.OPTION_DISABLED, true); account.setOption(Account.OPTION_MAGIC_CREATE, true); xmppConnectionService.createAccount(account); } Intent intent = new Intent(MagicCreateActivity.this, EditAccountActivity.class); intent.putExtra("jid", account.getJid().toBareJid().toString()); intent.putExtra("init", true); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); Toast.makeText(MagicCreateActivity.this, R.string.secure_password_generated, Toast.LENGTH_SHORT).show(); startActivity(intent); } catch (InvalidJidException e) { mUsername.setError(getString(R.string.invalid_username)); mUsername.requestFocus(); } } } }); mUsername.addTextChangedListener(this); } private String createPassword() { StringBuilder builder = new StringBuilder(PW_LENGTH); for(int i = 0; i < PW_LENGTH; ++i) { builder.append(CHARS.charAt(mRandom.nextInt(CHARS.length() - 1))); } return builder.toString(); } @Override public void beforeTextChanged(CharSequence s, int start, int count, int after) { } @Override public void onTextChanged(CharSequence s, int start, int before, int count) { } @Override public void afterTextChanged(Editable s) { if (s.toString().trim().length() > 0) { try { mFullJidDisplay.setVisibility(View.VISIBLE); Jid jid = Jid.fromParts(s.toString().toLowerCase(), Config.MAGIC_CREATE_DOMAIN, null); mFullJidDisplay.setText(getString(R.string.your_full_jid_will_be, jid.toString())); } catch (InvalidJidException e) { mFullJidDisplay.setVisibility(View.INVISIBLE); } } else { mFullJidDisplay.setVisibility(View.INVISIBLE); } } }
... on_enterイベントによってトリガーされます(アクティビティが表示されたとき):
<StartScreen>: … ScreenManager: … CreateAccount: on_enter: self._on_enter(action_bar, app, root_manager) …
また、テキストフィールドの値が変更された場合のon_textイベントにも関心があります。
<CreateAccount>: … SingleLineTextField: … on_text: app.check_len_login_in_textfield(self)
アプリケーションのメインクラスのcheck_len_login_in_textfieldメソッド:
def check_len_login_in_textfield(self, instance_textfield): # 20 . if len(instance_textfield.text) > 20: instance_textfield.text = instance_textfield.text[:20] # # . instance_textfield.message = 'username@conversations.im' \ if instance_textfield.text == '' \ else '{}@conversations.im'.format(instance_textfield.text)
したがって、テキストフィールドデータが正しい場合は、アクティビティAddAccountを表示します。
MDFlatButton: … on_release: if … … else: app.screen_root_manager.current = 'Add account'
それ以外の場合、不正なデータに関するメッセージが表示されます。
MDFlatButton: … on_release: if username.text == '' or username.text.isspace(): \ snackbar.make(app.data.string_lang_not_valid_username) …
さて、そして最後に、最後のアクティビティが残っています...
オリジナル:
Kivy:
はい、これは1つのアクティビティです。 2番目から、画面に表示されたら、プログラムで「余分な」テキストフィールドを削除します。
<StartScreen>: … ScreenManager: … AddAccount: id: add_account on_enter: self._on_enter(action_bar, app) on_leave: action_bar.title = app.data.string_lang_create_account AddAccountOwn: id: add_account_own_provider on_enter: self._on_enter(action_bar, app, root_manager) on_leave: action_bar.title = app.title; action_bar.left_action_items = []
マークアップファイルで、アクティビティテンプレートを作成しました。
<AddAccount>: name: 'Add account' AddAccountRoot: id: add_account_root
<AddAccountOwn>: name: 'Add account own provider' AddAccountRoot: id: add_account_root
アクティビティAddAccountRootからそれらを「継承」します。
#: kivy 1.9.1 #: import progress libs.uix.dialogs.dialog_progress #: import MDFlatButton kivymd.button.MDFlatButton #: import SingleLineTextField kivymd.textfields.SingleLineTextField #: import MDCheckbox kivymd.selectioncontrols.MDCheckbox # Activity . <AddAccountRoot@BoxLayout>: canvas: Color: rgba: app.data.background Rectangle: size: self.size pos: self.pos orientation: 'vertical' padding: dp(10), dp(10) BoxLayout: id: box canvas: Color: rgba: app.data.rectangle Rectangle: size: self.size pos: self.pos Color: rgba: app.data.list_color Rectangle: size: self.size[0] - 2, self.size[1] - 2 pos: self.pos[0] + 1, self.pos[1] + 1 orientation: 'vertical' size_hint_y: None padding: dp(10), dp(10) spacing: dp(15) height: app.window.height // 2 SingleLineTextField: id: username hint_text: 'Username' on_text: if self.message != '': app.check_len_login_in_textfield(self) SingleLineTextField: id: password hint_text: 'Password' password: True BoxLayout: id: box_check size_hint_y: None height: dp(40) MDCheckbox: id: check size_hint: None, None size: dp(40), dp(40) active: True on_state: if self.active: box.add_widget(confirm_password) else: box.remove_widget(confirm_password) if username.message != '': confirm_password.hint_text = 'Confirm password' Label: text: 'Register new account on server' valign: 'middle' color: app.data.text_color size_hint_x: .9 text_size: self.size[0] - 10, self.size[1] SingleLineTextField: id: confirm_password password: True Widget: Widget: BoxLayout: padding: dp(0), dp(10) MDFlatButton: text: app.data.string_lang_cancel theme_text_color: 'Primary' on_release: if app.screen.ids.root_manager.current == 'Add account own provider': \ app.screen.ids.root_manager.current = 'Start screen'; \ app.screen.ids.action_bar.title = app.title else: \ app.screen.ids.root_manager.current = 'Create account'; app.screen.ids.action_bar.title = app.data.string_lang_create_account MDFlatButton: text: app.data.string_lang_next on_release: instance_progress, instance_text_wait = \ progress(text_wait=app.data.string_lang_text_wait.format(app.data.text_color_hex), \ events_callback=lambda x: instance_progress.dismiss())
Kivy canvas . , : . Activity , , ( , ). .
:
MDCheckbox: … on_state: # True/False — / if self.active: box.add_widget(confirm_password) else: box.remove_widget(confirm_password) …
Activity AddAccount , :
from kivy.uix.screenmanager import Screen from kivy.clock import Clock class AddAccount(Screen): def _on_enter(self, instance_toolbar, instance_program): instance_toolbar.title = self.name self.ids.add_account_root.ids.username.focus = True # . Clock.schedule_once(instance_program.set_text_on_textfields, .5)
:
def set_focus_on_textfield(self, interval=0, instance_textfield=None, focus=True): if instance_textfield: instance_textfield.focus = focus def set_text_on_textfields(self, interval): add_account_root = self.screen.ids.add_account.ids.add_account_root field_username = add_account_root.ids.username field_password = add_account_root.ids.password field_confirm_password = add_account_root.ids.confirm_password field_username.text = self.screen.ids.create_account.ids.username.text.lower() field_password.focus = True password = self.generate_password() field_password.text = password field_confirm_password.text = password Clock.schedule_once( lambda x: self.set_focus_on_textfield( instance_textfield=field_password, focus=False), .5 ) Clock.schedule_once( lambda x: self.set_focus_on_textfield( instance_textfield=field_username), .5 )
! Activity , , . これは私自身です。 . , Kivy , , , .
, PyConversations , . じゃあね!
PyConversations github.