Skip to content

Commit bc2abdc

Browse files
committed
Properties extensions for Activity/View/Fragment/Resources
Signed-off-by: Fung <fython@163.com>
1 parent b6998e9 commit bc2abdc

File tree

8 files changed

+221
-16
lines changed

8 files changed

+221
-16
lines changed

build.gradle

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// Top-level build file where you can add configuration options common to all sub-projects/modules.
22

33
buildscript {
4-
ext.kotlin_version = '1.1.2'
4+
ext.kotlin_version = '1.1.4'
55
ext.android_support_lib_version = '26.0.0'
66
repositories {
77
jcenter()

demo/src/main/kotlin/moe/feng/kotlinyan/GlideExtDemoFragment.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ import android.widget.ImageView
99
import com.bumptech.glide.load.engine.DiskCacheStrategy
1010
import moe.feng.kotlinyan.common.AndroidExtensions
1111
import moe.feng.kotlinyan.common.GlideExtensions
12+
import moe.feng.kotlinyan.common.findNonNullView
1213
import org.jetbrains.anko.sdk25.coroutines.onClick
1314

1415
class GlideExtDemoFragment : Fragment(), GlideExtensions, AndroidExtensions {
1516

17+
private val imageView: ImageView by findNonNullView(R.id.image_lazy_load)
18+
1619
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View
1720
= inflater.inflate(R.layout.fragment_picasso_ext, container, false)
1821

1922
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
20-
val imageView = view[R.id.image_lazy_load] as ImageView
2123
imageView.placeholderResource = R.mipmap.ic_launcher
2224
imageView.glideBuilderTransform {
2325
animate(android.R.anim.fade_in)

demo/src/main/kotlin/moe/feng/kotlinyan/MainActivity.kt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -12,13 +12,13 @@ import android.view.Menu
1212
import android.view.MenuItem
1313
import moe.feng.kotlinyan.common.AndroidExtensions
1414
import moe.feng.kotlinyan.common.ColorExtensions
15-
import org.jetbrains.anko.find
15+
import moe.feng.kotlinyan.common.lazyFindNonNullView
1616
import org.jetbrains.anko.toast
1717

1818
class MainActivity : AppCompatActivity(), AndroidExtensions, ColorExtensions {
1919

20-
val tabLayout by lazy { find<TabLayout>(R.id.tab_layout) }
21-
val viewPager by lazy { find<ViewPager>(R.id.view_pager) }
20+
private val tabLayout: TabLayout by lazyFindNonNullView(R.id.tab_layout)
21+
private val viewPager: ViewPager by lazyFindNonNullView(R.id.view_pager)
2222

2323
override fun onCreate(savedInstanceState: Bundle?) {
2424
super.onCreate(savedInstanceState)

demo/src/main/kotlin/moe/feng/kotlinyan/PicassoExtDemoFragment.kt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,15 +9,17 @@ import android.widget.ImageView
99
import com.squareup.picasso.MemoryPolicy
1010
import moe.feng.kotlinyan.common.AndroidExtensions
1111
import moe.feng.kotlinyan.common.PicassoExtensions
12+
import moe.feng.kotlinyan.common.findNonNullView
1213
import org.jetbrains.anko.sdk25.coroutines.onClick
1314

1415
class PicassoExtDemoFragment : Fragment(), PicassoExtensions, AndroidExtensions {
1516

17+
private val imageView: ImageView by findNonNullView(R.id.image_lazy_load)
18+
1619
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View
1720
= inflater.inflate(R.layout.fragment_picasso_ext, container, false)
1821

1922
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
20-
val imageView = view[R.id.image_lazy_load] as ImageView
2123
imageView.enableMaterialPicassoAnimation()
2224
imageView.placeholderResource = R.mipmap.ic_launcher
2325
imageView.picassoRequestTransform {

demo/src/main/kotlin/moe/feng/kotlinyan/ViewExtDemoFragment.kt

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -11,42 +11,44 @@ import android.widget.EditText
1111
import android.widget.TextView
1212
import moe.feng.kotlinyan.common.AndroidExtensions
1313
import moe.feng.kotlinyan.common.ViewExtensions
14+
import moe.feng.kotlinyan.common.findNonNullView
15+
import moe.feng.kotlinyan.common.stringRes
1416
import org.jetbrains.anko.sdk25.coroutines.onClick
1517

1618
class ViewExtDemoFragment : Fragment(), ViewExtensions, AndroidExtensions {
1719

18-
lateinit var keyboardTestEdit : EditText
20+
private val keyboardTestEdit: EditText by findNonNullView(R.id.keyboard_test_edit)
21+
22+
private val pxToDpFormat by stringRes(R.string.px_to_dp_text)
23+
private val dpToPxFormat by stringRes(R.string.dp_to_px_text)
24+
private val pxToSpFormat by stringRes(R.string.px_to_sp_text)
25+
private val spToPxFormat by stringRes(R.string.sp_to_px_text)
1926

2027
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup, savedInstanceState: Bundle?): View
2128
= inflater.inflate(R.layout.fragment_view_ext, container, false)
2229

2330
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
24-
keyboardTestEdit = view[R.id.keyboard_test_edit] as EditText
2531
view[R.id.show_keyboard].onClick { keyboardTestEdit.showKeyboard() }
2632
view[R.id.hide_keyboard].onClick { keyboardTestEdit.hideKeyboard() }
2733

2834
(view[R.id.edit_px_to_dp] as EditText).onTextChanged {
2935
val from = it.toString().toFloatOrNull() ?: 0F
30-
(view[R.id.result_px_to_dp] as TextView).text =
31-
resources.string[R.string.px_to_dp_text]!!.format(from, from.pxToDp(activity))
36+
(view[R.id.result_px_to_dp] as TextView).text = pxToDpFormat.format(from, from.pxToDp(activity))
3237
}
3338

3439
(view[R.id.edit_dp_to_px] as EditText).onTextChanged {
3540
val from = it.toString().toFloatOrNull() ?: 0F
36-
(view[R.id.result_dp_to_px] as TextView).text =
37-
resources.string[R.string.dp_to_px_text]!!.format(from, from.dpToPx(activity))
41+
(view[R.id.result_dp_to_px] as TextView).text = dpToPxFormat.format(from, from.dpToPx(activity))
3842
}
3943

4044
(view[R.id.edit_px_to_sp] as EditText).onTextChanged {
4145
val from = it.toString().toFloatOrNull() ?: 0F
42-
(view[R.id.result_px_to_sp] as TextView).text =
43-
resources.string[R.string.px_to_sp_text]!!.format(from, from.pxToSp(activity))
46+
(view[R.id.result_px_to_sp] as TextView).text = pxToSpFormat.format(from, from.pxToSp(activity))
4447
}
4548

4649
(view[R.id.edit_sp_to_px] as EditText).onTextChanged {
4750
val from = it.toString().toFloatOrNull() ?: 0F
48-
(view[R.id.result_sp_to_px] as TextView).text =
49-
resources.string[R.string.sp_to_px_text]!!.format(from, from.spToPx(activity))
51+
(view[R.id.result_sp_to_px] as TextView).text = spToPxFormat.format(from, from.spToPx(activity))
5052
}
5153
}
5254

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package moe.feng.kotlinyan.common
2+
3+
import android.annotation.TargetApi
4+
import android.graphics.Typeface
5+
import android.graphics.drawable.Drawable
6+
import android.support.v4.app.Fragment
7+
import android.view.View
8+
9+
fun <T: View> Fragment.findView(viewId: Int): LazyGetView<Fragment, T?> {
10+
return LazyGetView(viewId, { fragment, id -> fragment.view?.findViewById(id) }, dontLazy = true)
11+
}
12+
13+
fun <T: View> Fragment.findNonNullView(viewId: Int): LazyGetNonNullView<Fragment, T> {
14+
return LazyGetNonNullView(viewId, { fragment, id -> fragment.view?.findViewById(id)!! }, dontLazy = true)
15+
}
16+
17+
fun Fragment.dimenRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Float>
18+
= ResourcesProperty(id, { resources.getDimension(it) }, loadOnlyOnce)
19+
fun Fragment.stringRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<String>
20+
= ResourcesProperty(id, { resources.getString(it) }, loadOnlyOnce)
21+
fun Fragment.integerRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
22+
= ResourcesProperty(id, { resources.getInteger(it) }, loadOnlyOnce)
23+
fun Fragment.boolRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Boolean>
24+
= ResourcesProperty(id, { resources.getBoolean(it) }, loadOnlyOnce)
25+
fun Fragment.drawableRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Drawable>
26+
= ResourcesProperty(id, { resources.getDrawable(it) }, loadOnlyOnce)
27+
fun Fragment.colorRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
28+
= ResourcesProperty(id, { resources.getColor(it) }, loadOnlyOnce)
29+
fun Fragment.stringArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Array<String>>
30+
= ResourcesProperty(id, { resources.getStringArray(it) }, loadOnlyOnce)
31+
fun Fragment.intArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<IntArray>
32+
= ResourcesProperty(id, { resources.getIntArray(it) }, loadOnlyOnce)
33+
@TargetApi(26) fun Fragment.fontRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Typeface>
34+
= ResourcesProperty(id, { resources.getFont(it) }, loadOnlyOnce)
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
package moe.feng.kotlinyan.common
2+
3+
import android.annotation.TargetApi
4+
import android.app.Activity
5+
import android.app.Fragment
6+
import android.content.Context
7+
import android.content.SharedPreferences
8+
import android.graphics.Typeface
9+
import android.graphics.drawable.Drawable
10+
import android.preference.Preference
11+
import android.preference.PreferenceManager
12+
import android.view.View
13+
import kotlin.properties.ReadOnlyProperty
14+
import kotlin.reflect.KProperty
15+
16+
// View Properties
17+
18+
fun <T: View> Activity.lazyFindView(viewId: Int): LazyGetView<Activity, T?> {
19+
return LazyGetView(viewId, { activity, id -> activity.findViewById(id) })
20+
}
21+
22+
fun <T: View> Activity.lazyFindNonNullView(viewId: Int): LazyGetNonNullView<Activity, T> {
23+
return LazyGetNonNullView(viewId, { activity, id -> activity.findViewById(id) })
24+
}
25+
26+
fun <T: View> Fragment.findView(viewId: Int): LazyGetView<Fragment, T?> {
27+
return LazyGetView(viewId, { fragment, id -> fragment.view.findViewById(id) }, dontLazy = true)
28+
}
29+
30+
fun <T: View> Fragment.findNonNullView(viewId: Int): LazyGetNonNullView<Fragment, T> {
31+
return LazyGetNonNullView(viewId, { fragment, id -> fragment.view.findViewById(id) }, dontLazy = true)
32+
}
33+
34+
fun <T: View> View.lazyFindView(viewId: Int): LazyGetView<View, T?> {
35+
return LazyGetView(viewId, { view, id -> view.findViewById(id) })
36+
}
37+
38+
fun <T: View> View.lazyFindNonNullView(viewId: Int): LazyGetNonNullView<View, T> {
39+
return LazyGetNonNullView(viewId, { view, id -> view.findViewById(id) })
40+
}
41+
42+
class LazyGetView<in R, out T: View?> (
43+
private val viewId: Int,
44+
private val getter: (R, Int) -> T?,
45+
private val dontLazy: Boolean = false
46+
): ReadOnlyProperty<R, T?> {
47+
48+
private var _value: T? = null
49+
50+
override fun getValue(thisRef: R, property: KProperty<*>): T? {
51+
if (_value == null || !dontLazy) _value = getter(thisRef, viewId)
52+
return _value
53+
}
54+
55+
}
56+
57+
class LazyGetNonNullView<in R, out T: View> (
58+
private val viewId: Int,
59+
private val getter: (R, Int) -> T,
60+
private val dontLazy: Boolean = false
61+
): ReadOnlyProperty<R, T> {
62+
63+
private var _value: T? = null
64+
65+
override fun getValue(thisRef: R, property: KProperty<*>): T {
66+
if (_value == null || dontLazy) _value = getter(thisRef, viewId)
67+
return _value!!
68+
}
69+
70+
}
71+
72+
// Preference Properties
73+
74+
class GetPreference<out T: Preference>(private val keyName: String)
75+
: ReadOnlyProperty<GetPreference.PreferenceObserver, T> {
76+
77+
override fun getValue(thisRef: PreferenceObserver, property: KProperty<*>): T {
78+
return thisRef.getPreferenceManager().findPreference(keyName) as T
79+
}
80+
81+
interface PreferenceObserver {
82+
fun getPreferenceManager(): PreferenceManager
83+
}
84+
85+
}
86+
87+
// Shared Preferences Properties
88+
89+
class GetSharedPreferences(private val prefName: String,
90+
private val mode: Int = Context.MODE_PRIVATE): ReadOnlyProperty<Context, SharedPreferences> {
91+
92+
override fun getValue(thisRef: Context, property: KProperty<*>): SharedPreferences {
93+
return thisRef.getSharedPreferences(prefName, mode)
94+
}
95+
96+
}
97+
98+
// Resources Properties
99+
100+
fun Context.dimenRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Float>
101+
= ResourcesProperty(id, resources::getDimension, loadOnlyOnce)
102+
fun Context.stringRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<String>
103+
= ResourcesProperty<String>(id, resources::getString, loadOnlyOnce)
104+
fun Context.integerRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
105+
= ResourcesProperty(id, resources::getInteger, loadOnlyOnce)
106+
fun Context.boolRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Boolean>
107+
= ResourcesProperty(id, resources::getBoolean, loadOnlyOnce)
108+
fun Context.drawableRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Drawable>
109+
= ResourcesProperty<Drawable>(id, resources::getDrawable, loadOnlyOnce)
110+
fun Context.colorRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
111+
= ResourcesProperty<Int>(id, resources::getColor, loadOnlyOnce)
112+
fun Context.stringArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Array<String>>
113+
= ResourcesProperty(id, resources::getStringArray, loadOnlyOnce)
114+
fun Context.intArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<IntArray>
115+
= ResourcesProperty(id, resources::getIntArray, loadOnlyOnce)
116+
@TargetApi(26) fun Context.fontRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Typeface>
117+
= ResourcesProperty(id, resources::getFont, loadOnlyOnce)
118+
119+
fun Fragment.dimenRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Float>
120+
= ResourcesProperty(id, { resources.getDimension(it) }, loadOnlyOnce)
121+
fun Fragment.stringRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<String>
122+
= ResourcesProperty(id, { resources.getString(it) }, loadOnlyOnce)
123+
fun Fragment.integerRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
124+
= ResourcesProperty(id, { resources.getInteger(it) }, loadOnlyOnce)
125+
fun Fragment.boolRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Boolean>
126+
= ResourcesProperty(id, { resources.getBoolean(it) }, loadOnlyOnce)
127+
fun Fragment.drawableRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Drawable>
128+
= ResourcesProperty(id, { resources.getDrawable(it) }, loadOnlyOnce)
129+
fun Fragment.colorRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Int>
130+
= ResourcesProperty(id, { resources.getColor(it) }, loadOnlyOnce)
131+
fun Fragment.stringArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Array<String>>
132+
= ResourcesProperty(id, { resources.getStringArray(it) }, loadOnlyOnce)
133+
fun Fragment.intArrayRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<IntArray>
134+
= ResourcesProperty(id, { resources.getIntArray(it) }, loadOnlyOnce)
135+
@TargetApi(26) fun Fragment.fontRes(id: Int, loadOnlyOnce: Boolean = true): ResourcesProperty<Typeface>
136+
= ResourcesProperty(id, { resources.getFont(it) }, loadOnlyOnce)
137+
138+
class ResourcesProperty<out T> (
139+
private val resourceId: Int,
140+
private val func: (resourceId: Int) -> T,
141+
private val loadOnlyOnce: Boolean = true): ReadOnlyProperty<Any, T> {
142+
143+
private var _value: T? = null
144+
145+
override fun getValue(thisRef: Any, property: KProperty<*>): T {
146+
if (_value == null || !loadOnlyOnce) _value = func(resourceId)
147+
return _value!!
148+
}
149+
150+
}

kotlinyan-common/src/main/kotlin/moe/feng/kotlinyan/common/ViewExtensions.kt

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,4 +144,19 @@ interface ViewExtensions: ServiceExtensions {
144144
}
145145
}
146146

147+
// ViewGroup extend
148+
operator fun ViewGroup.plusAssign(view: View) {
149+
addView(view)
150+
}
151+
152+
operator fun ViewGroup.minusAssign(view: View) {
153+
removeView(view)
154+
}
155+
156+
fun ViewGroup.forEach(consumer: (View) -> Unit) = forEachIndexed { _, view -> consumer(view) }
157+
158+
fun ViewGroup.forEachIndexed(consumer: (index: Int, view: View) -> Unit) {
159+
for (index in 0..(childCount - 1)) consumer(index, this.getChildAt(index))
160+
}
161+
147162
}

0 commit comments

Comments
 (0)