可以将文章内容翻译成中文,广告屏蔽插件可能会导致该功能失效(如失效,请关闭广告屏蔽插件后再试):
问题:
I'm trying to use Kotlin with Butterknife for my Android Application.
Here is my build.gradle
dependencies {
...
compile 'com.jakewharton:butterknife:8.0.1'
kapt 'com.jakewharton:butterknife-compiler:8.0.1'
}
kapt {
generateStubs = true
}
I also has an EditText and I want to show a message using ButterKnife when it is changed:
@OnTextChanged(R.id.input)
fun test() {
toast(1)
}
However, nothing happens. I put a breakpoint into the function - and it is not even executed.
P.S: I have heard about kotterknife, however I have seen an example with pure Butterknife.
What am I doing wrong?
回答1:
There's no need for butterknife in Kotlin. You can directly use the following:
// app:build.gradle file
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
compileSdkVersion 26
buildToolsVersion "26.0.1"
defaultConfig {
applicationId "com.example.nikhiljadhav.myapplication"
minSdkVersion 15
targetSdkVersion 26
versionCode 1
versionName "1.0"
testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
}
}
}
dependencies {
implementation fileTree(include: ['*.jar'], dir: 'libs')
implementation "org.jetbrains.kotlin:kotlin-stdlib-jre7:$kotlin_version"
implementation 'com.android.support:appcompat-v7:26.0.0'
implementation 'com.android.support.constraint:constraint-layout:1.0.2'
implementation 'com.android.support:design:26.0.0'
testImplementation 'junit:junit:4.12'
androidTestImplementation 'com.android.support.test:runner:1.0.0'
androidTestImplementation 'com.android.support.test.espresso:espresso-core:3.0.0'
}
kapt {
generateStubs = true
}
// xml layout file
<TextView
android:id="@+id/tvHello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" />
<TextView
android:id="@+id/tvId"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" />
<EditText
android:id="@+id/etDemo"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="8dp"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp"
android:onClick="onClick"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" />
// MainActivity.kt file
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
setSupportActionBar(toolbar)
// use the kotlin property
tvHello.text="Hi bla bla"
tvId.text="buubububub"
//set textcolor
tvId.setTextColor(ContextCompat.getColor(this, R.color.colorAccent))
etDemo.hint="nhdodfhfgf"
tvId.setOnClickListener{ view->
onClick(view)
}
fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
}
fun onClick(view: View) {
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
...
}
For onTextChangeListner:
etText.addTextChangedListener(object : TextWatcher{
override fun afterTextChanged(p0: Editable?) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun beforeTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun onTextChanged(p0: CharSequence?, p1: Int, p2: Int, p3: Int) {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
})
回答2:
In your app level build.gradle
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-kapt'
kapt {
generateStubs = true
}
dependencies {
compile 'com.jakewharton:butterknife:10.2.0'
kapt 'com.jakewharton:butterknife-compiler:10.2.0'
}
In your Top Level build.gradle
buildscript {
ext.kotlin_version = '1.3.30'
repositories {
jcenter()
}
dependencies {
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
}
}
Activity
@BindView(R.id.toolbar) @JvmField var toolbar: Toolbar? = null
or
@BindView(R.id.toolbar) lateinit var toolbar: Toolbar
Inside OnCreate
ButterKnife.bind(this)
回答3:
Kotlin creators tell on their site that:
Kotlin Android Extensions plugin (automatically bundled into the Kotlin plugin in Android Studio) solves the same issue: replacing findViewById
with a concise and straightforward code. Consider using it unless you're already using ButterKnife and don't want to migrate.
and e.g.
// Using R.layout.activity_main from the main source set
import kotlinx.android.synthetic.main.activity_main.*
class MyActivity : Activity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
textView.setText("Hello, world!")
// Instead of findViewById(R.id.textView) as TextView
}
}
textView
is an extension property for Activity
, and it has the same type as declared in activity_main.xml
.
回答4:
In your gradle:
compile 'com.jakewharton:butterknife:8.8.0'
kapt "com.jakewharton:butterknife-compiler:8.8.0"
In your activity
@BindView(R.id.toolbar)
lateinit var mToolbar: Toolbar
Of course, remember ButterKnife.bind(this)
and apply the plugin on the top of your app.gradle apply plugin: 'kotlin-kapt'
Check full example
Full Link: https://github.com/JetBrains/kotlin-examples/tree/master/gradle/android-butterknife
回答5:
You need to simply add ButterKnife.kt
into your source tree from the following link:
https://github.com/JakeWharton/kotterknife
It worked for me.
回答6:
Add this in your Project Build.gradle
buildscript {
ext.kotlin_version = '1.1.2-4'
ext.butterknife_version = '8.6.0'
repositories {
maven { url 'https://maven.google.com' }
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:3.0.0-alpha1'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
classpath "com.jakewharton:butterknife-gradle-plugin:$butterknife_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
And in your app Build.Gradle add this.
//Butterknife
compile "com.jakewharton:butterknife:$butterknife_version"
kapt "com.jakewharton:butterknife-compiler:$butterknife_version"
回答7:
you can import all synthetic properties for the free/res/layout/activity_main.xml layout by adding this import:
import kotlinx.android.synthetic.main.activity_main.*
Now you can access all views by using there id's no need to initiate findbyid
回答8:
You can implement some extensions to improve your views behavior. Checkout this example for "onTextChange" in a regular editText:
fun EditText.onTextChange(callback: (text: CharSequence?, start: Int, before: Int, count: Int) -> Unit) {
addTextChangedListener(object : TextWatcher {
override fun afterTextChanged(s: Editable?) {}
override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {
callback(s, start, before, count)
}
})
}
Usage:
m_editText.onTextChange { text, _, _, _ ->
m_textView.text = text
}
I vote for kotlin-android-extensions
回答9:
Jake Wharton created new library for kotlin called kotterknife:
https://github.com/JakeWharton/kotterknife
Gradle:
compile 'com.jakewharton:kotterknife:0.1.0-SNAPSHOT'
View:
val lastName: TextView by bindView(R.id.last_name)
// Optional binding.
val details: TextView? by bindOptionalView(R.id.details)
// List binding.
val nameViews: List<TextView> by bindViews(R.id.first_name, R.id.last_name)
// List binding with optional items being omitted.
val nameViews: List<TextView> by bindOptionalViews(R.id.first_name, R.id.middle_name, R.id.last_name)
回答10:
In Kotlin, actually there is no need (or) necessity for going ButterKnife concepts. because in your activity you can directly refer the view _id of the layout file as referred below.
layout.xml
<Button
android:id="@+id/btn_prestage"
android:layout_width="20dp"
android:layout_height="20dp"
android:background="@drawable/prestaging_off"/>
Activity.kt
btn_prestage.setBackgroundResource(R.drawable.staging_on)
btn_prestage.setOnClickListener{ view ->
Snackbar.make(view, "My Action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show() }
build.gradle(app)
apply plugin: 'com.android.application'
apply plugin: 'kotlin-android'
apply plugin: 'kotlin-android-extensions'
apply plugin: 'kotlin-kapt'
android {
dependencies {... }
}
kapt {
generateStubs = true
}