Commit 8d4a1ad6 authored by Mygod's avatar Mygod

DropDownPreference

parent 0f0c9edb
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="SummaryPreference">
<attr name="summary" format="string" />
</declare-styleable>
<declare-styleable name="DropDownPreference">
<attr name="entries" format="reference" />
<attr name="entryValues" format="reference" />
</declare-styleable>
</resources>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res/com.github.shadowsocks">
<PreferenceCategory <PreferenceCategory
android:title="@string/proxy_cat"> android:title="@string/proxy_cat">
...@@ -37,28 +38,28 @@ ...@@ -37,28 +38,28 @@
android:summary="@string/sitekey_summary" android:summary="@string/sitekey_summary"
android:title="@string/sitekey"> android:title="@string/sitekey">
</com.github.shadowsocks.preferences.PasswordEditTextPreference> </com.github.shadowsocks.preferences.PasswordEditTextPreference>
<ListPreference <com.github.shadowsocks.preferences.DropDownPreference
android:defaultValue="rc4" android:defaultValue="rc4"
android:key="encMethod" android:key="encMethod"
android:entries="@array/enc_method_entry" app:entries="@array/enc_method_entry"
android:entryValues="@array/enc_method_value" app:entryValues="@array/enc_method_value"
android:summary="%s" app:summary="%s"
android:title="@string/enc_method"> android:title="@string/enc_method">
</ListPreference> </com.github.shadowsocks.preferences.DropDownPreference>
</PreferenceCategory> </PreferenceCategory>
<PreferenceCategory <PreferenceCategory
android:title="@string/feature_cat"> android:title="@string/feature_cat">
<ListPreference <com.github.shadowsocks.preferences.DropDownPreference
android:defaultValue="all" android:defaultValue="all"
android:key="route" android:key="route"
android:entries="@array/route_entry" app:entries="@array/route_entry"
android:entryValues="@array/route_value" app:entryValues="@array/route_value"
android:summary="%s" app:summary="%s"
android:title="@string/route_list"> android:title="@string/route_list">
</ListPreference> </com.github.shadowsocks.preferences.DropDownPreference>
<SwitchPreference <SwitchPreference
android:key="isIpv6" android:key="isIpv6"
android:defaultValue="false" android:defaultValue="false"
......
package com.github.shadowsocks.preferences
import android.annotation.TargetApi
import android.content.Context
import android.content.res.TypedArray
import android.os.Build
import android.preference.Preference
import android.support.annotation.NonNull
import android.support.v7.widget.AppCompatSpinner
import android.util.AttributeSet
import android.view.{View, ViewGroup}
import android.widget.AdapterView.OnItemSelectedListener
import android.widget.{AdapterView, ArrayAdapter}
import com.github.shadowsocks.R
import com.github.shadowsocks.utils.Utils
/**
* Based on: https://github.com/Mygod/mygod-lib-android/blob/683c41cb86d10e99ab0f457d41a218c6915fccc8/lib/src/main/scala/tk/mygod/preference/DropDownPreference.scala
* @author Mygod
*/
final class DropDownPreference(private val mContext: Context, attrs: AttributeSet = null)
extends Preference(mContext, attrs) with SummaryPreference {
private val mAdapter = new ArrayAdapter[String](mContext, android.R.layout.simple_spinner_dropdown_item)
private val mSpinner = new AppCompatSpinner(mContext)
private var mEntries: Array[CharSequence] = _
private var mEntryValues: Array[CharSequence] = _
private var mSelectedIndex: Int = _
private var mValueSet: Boolean = _
mSpinner.setVisibility(View.INVISIBLE)
mSpinner.setAdapter(mAdapter)
mSpinner.setOnItemSelectedListener(new OnItemSelectedListener {
override def onNothingSelected(parent: AdapterView[_]) { }
override def onItemSelected(parent: AdapterView[_], view: View, position: Int, id: Long) = setValueIndex(position)
})
setOnPreferenceClickListener((preference: Preference) => {
mSpinner.setDropDownVerticalOffset(Utils.dpToPx(getContext, 8 - 48 * mSelectedIndex).toInt) // TODO: scrolling?
mSpinner.performClick
true
})
initSummary(mContext, attrs)
val a: TypedArray = mContext.obtainStyledAttributes(attrs, R.styleable.DropDownPreference)
setEntries(a.getTextArray(R.styleable.DropDownPreference_entries))
mEntryValues = a.getTextArray(R.styleable.DropDownPreference_entryValues)
a.recycle
protected override def getSummaryValue = getEntry
/**
* Sets the human-readable entries to be shown in the list. This will be shown in subsequent dialogs.
*
* Each entry must have a corresponding index in [[setEntryValues(CharSequence[])]].
*
* @param entries The entries.
* @see [[setEntryValues(CharSequence[])]]
*/
def setEntries(entries: Array[CharSequence]) {
mEntries = entries
mAdapter.clear
if (entries != null) for (entry <- entries) mAdapter.add(entry.toString)
}
/**
* @see #setEntries(CharSequence[])
* @param entriesResId The entries array as a resource.
*/
def setEntries(entriesResId: Int): Unit = setEntries(getContext.getResources.getTextArray(entriesResId))
/**
* The list of entries to be shown in the list in subsequent dialogs.
*
* @return The list as an array.
*/
def getEntries = mEntries
/**
* The array to find the value to save for a preference when an entry from
* entries is selected. If a user clicks on the second item in entries, the
* second item in this array will be saved to the preference.
*
* @param entryValues The array to be used as values to save for the preference.
*/
def setEntryValues(entryValues: Array[CharSequence]) = mEntryValues = entryValues
/**
* @see #setEntryValues(CharSequence[])
* @param entryValuesResId The entry values array as a resource.
*/
def setEntryValues(entryValuesResId: Int): Unit =
setEntryValues(getContext.getResources.getTextArray(entryValuesResId))
/**
* Returns the array of values to be saved for the preference.
*
* @return The array of values.
*/
def getEntryValues: Array[CharSequence] = mEntryValues
/**
* Sets the value of the key. This should be one of the entries in [[getEntryValues]].
*
* @param value The value to set for the key.
*/
def setValue(value: String) {
val i = findIndexOfValue(value)
if (i > -1) setValueIndex(i)
}
/**
* Sets the value to the given index from the entry values.
*
* @param index The index of the value to set.
*/
def setValueIndex(index: Int) {
val changed = mSelectedIndex != index
if (changed || !mValueSet) {
mSelectedIndex = index
mValueSet = true
if (mEntryValues != null) {
val value = mEntryValues(index).toString
persistString(value)
setValue(value)
}
if (changed) notifyChanged
}
mSpinner.setSelection(index)
}
/**
* Returns the value of the key. This should be one of the entries in [[getEntryValues]].
*
* @return The value of the key.
*/
def getValue = if (mEntryValues == null) null else mEntryValues(mSelectedIndex).toString
/**
* Returns the entry corresponding to the current value.
*
* @return The entry corresponding to the current value, or null.
*/
def getEntry = {
val index = getValueIndex
if (index >= 0 && mEntries != null) mEntries(index) else null
}
/**
* Returns the index of the given value (in the entry values array).
*
* @param value The value whose index should be returned.
* @return The index of the value, or -1 if not found.
*/
def findIndexOfValue(value: String): Int = {
if (value != null && mEntryValues != null) {
var i = mEntryValues.length - 1
while (i >= 0) {
if (mEntryValues(i) == value) return i
i -= 1
}
}
-1
}
def getValueIndex = mSelectedIndex
protected override def onGetDefaultValue(a: TypedArray, index: Int) = a.getString(index)
protected override def onSetInitialValue (restoreValue: Boolean, defaultValue: AnyRef) =
setValue(if (restoreValue) getPersistedString(getValue) else defaultValue.asInstanceOf[String])
@TargetApi(Build.VERSION_CODES.JELLY_BEAN)
def setDropDownWidth(dimenResId: Int) =
mSpinner.setDropDownWidth(mContext.getResources.getDimensionPixelSize(dimenResId))
protected override def onBindView(@NonNull view: View) {
super.onBindView(view)
if (view == mSpinner.getParent) return
if (mSpinner.getParent != null) mSpinner.getParent.asInstanceOf[ViewGroup].removeView(mSpinner)
view.asInstanceOf[ViewGroup].addView(mSpinner, 0)
val lp = mSpinner.getLayoutParams
lp.width = 0
mSpinner.setLayoutParams(lp)
}
}
package com.github.shadowsocks.preferences
import android.content.Context
import android.preference.Preference
import android.util.AttributeSet
import com.github.shadowsocks.R
/**
* Make your preference support %s in summary. Override getSummaryValue to customize what to put in.
* Based on: https://github.com/Mygod/mygod-lib-android/blob/eb20c57a0da70bb5dbc27104002f20fb1eb31d76/lib/src/main/scala/tk/mygod/preference/SummaryPreference.scala
* @author Mygod
*/
trait SummaryPreference extends Preference {
private var mSummary: String = _
protected def initSummary(context: Context, attrs: AttributeSet) {
val a = context.obtainStyledAttributes(attrs, R.styleable.SummaryPreference)
mSummary = a.getString(R.styleable.SummaryPreference_summary)
a.recycle
}
protected def getSummaryValue: AnyRef
/**
* Returns the summary of this SummaryPreference. If the summary has a String formatting marker in it
* (i.e. "%s" or "%1$s"), then the current entry value will be substituted in its place.
*
* @return the summary with appropriate string substitution
*/
override def getSummary = {
val entry = getSummaryValue
if (mSummary == null || entry == null) super.getSummary else String.format(mSummary, entry)
}
/**
* Sets the summary for this Preference with a CharSequence. If the summary has a String formatting marker in it
* (i.e. "%s" or "%1$s"), then the current entry value will be substituted in its place when it's retrieved.
*
* @param summary The summary for the preference.
*/
override def setSummary(summary: CharSequence) {
super.setSummary(summary)
if (summary == null && mSummary != null) mSummary = null
else if (summary != null && summary != mSummary) mSummary = summary.toString
}
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment