I'm trying to get worked a segmented SeekBar for font site with step of 2.
It's working, but I can't keep thumb position, it is always on 0.
private fun fontSize() {
val view = LayoutInflater.from(this).inflate(R.layout.font_size_layout, null)
size = view.findViewById(R.id.font_size_sb)
val preference = PrefManager(this)
font = view.findViewById(R.id.font_size_tv)
font.textSize = preference.getFontSize().toFloat()
font.text = preference.getFontSize().toString()
size.apply {
max = (36 - 12) / 2
progress = preference.getFontSize()
setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
updateFontSize(12 + (progress * 2))
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
AlertDialog.Builder(
this,
R.style.AlertDialogSlider
).apply {
setView(view)
create()
show()
}
}
private fun updateFontSize(i: Int) {
note.textSize = i.toFloat()
font.text = i.toString()
font.textSize = i.toFloat()
preference.saveFontSize(i)
}
My preference class PrefManager:
class PrefManager(private var context: Context) {
fun saveFontSize(size: Int) {
context.getSharedPreferences("font_size", AppCompatActivity.MODE_PRIVATE).edit().apply {
putInt("fontSize", size)
apply()
}
}
fun getFontSize(): Int {
return context.getSharedPreferences("font_size", AppCompatActivity.MODE_PRIVATE)
.getInt("fontSize", -1)
}
For example, I set the font size to 18:
That's good and works for me, but when I want to change the size one more time, the SeekBar's position does not stay there, where I left it lastly. It goes to end:
How can I keep the position?
After spending a lot of time, I finally found a solution and it's very simple:
class PrefManager(private var context: Context) {
fun saveFontSize(size: Int, progress: Int) {
context.getSharedPreferences("font_size", AppCompatActivity.MODE_PRIVATE).edit().apply {
putInt("fontSize", size)
putInt("progress", progress)
apply()
}
}
fun getFontSize(): Int {
return context.getSharedPreferences("font_size", AppCompatActivity.MODE_PRIVATE)
.getInt("fontSize", 18)
}
fun getProgress(): Int {
return context.getSharedPreferences("font_size", AppCompatActivity.MODE_PRIVATE)
.getInt("progress", 3)
}
}
And piece of code for SeekBar:
size.apply {
progress = preference.getProgress()
setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(
seekBar: SeekBar?,
progress: Int,
fromUser: Boolean
) {
val fontSize = 12 + (progress * 2)
note.textSize = fontSize.toFloat()
font.text = fontSize.toString()
preference.saveFontSize(fontSize, progress)
}
override fun onStartTrackingTouch(seekBar: SeekBar?) {
}
override fun onStopTrackingTouch(seekBar: SeekBar?) {
}
})
}
I had just to keep saved the original values of progress within the onProgressChanged(). That's all!
Related
What I would want to do:
I would want to filter through list and show values that match the search phrase. Additionally I would want to show correct current list size in the UI.
What is the issue:
The issue is that I can filter through list, but on UI, my list size doesn't update. For example if I've downloaded 5 items to offline mode, it would show that there are still 5 items total, but there would be only 2 for example (and only 2 visible on the screen).
The next issue is that if I try to empty the search bar, the list doesn't go back to it's initial state. It's just empty and list size on UI shows that there are 5 items.
What I've tried:
I've tried adding notifyDataSetChanged() in adapter, but it doesn't work as intended. While debugging, The list is filtered and list after filtering is smaller, but it doesn't emit that value to the fragment.
Adapter:
class OssOfflineDevicesListAdapter(
private val offlineDevices: MutableList<OssOfflineDevicesI> = mutableListOf(),
private val removeDevicesFromQueue: (Long) -> Unit,
private val retryDownloadingDevices: (Long) -> Unit
) : RecyclerView.Adapter<OssOfflineDevicesListAdapter.OssOfflineDevicesListItemViewHolder>() {
private val filteredDevices: MutableList<OssOfflineDevicesI> = offlineDevices
override fun getItemCount(): Int = filteredDevices.size
fun filter(searchPhrase: String) {
val newOfflineDevices = offlineDevices.filter {
it.name().contains(searchPhrase, true)
}
updateListView(newOfflineDevices)
filteredDevices.clear()
filteredDevices.addAll(newOfflineDevices)
notifyDataSetChanged()
}
fun update(newValues: List<OssOfflineDevicesI>) {
updateListView(newValues)
filteredDevices.clear()
filteredDevices.addAll(newValues)
notifyDataSetChanged()
}
private fun updateListView(newValues: List<OssOfflineDevicesI>) {
DiffUtil.calculateDiff(object : DiffUtil.Callback() {
override fun getOldListSize(): Int = filteredDevices.size
override fun getNewListSize(): Int = newValues.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return filteredDevices[oldItemPosition].id() == newValues[newItemPosition].id()
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldDevices = filteredDevices[oldItemPosition]
val newDevices = newValues[newItemPosition]
return oldDevices.externalId() == newDevices.externalId() &&
oldDevices.downloadingStatus() == newDevices.downloadingStatus() &&
oldDevices.name() == newDevices.name()
}
}).dispatchUpdatesTo(this)
}
Fragment:
class OssOfflineDevicesListFragment : CoreFragment() {
private val disposableBag = CompositeDisposable()
private val viewModel by viewModel<OssOfflineDevicesListViewModel>()
private val offlineDevicesListAdapter = OssOfflineDevicesListAdapter(
removeDevicesFromQueue = { devicesExternalId -> removeDevicesFromQueue(devicesExternalId) },
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
setUpUI()
observeOssActionTransmitter()
setUpQuickSearch()
viewModel.offlineDevices().observe(viewLifecycleOwner, { offlineDevices ->
if (offlineDevices.isNullOrEmpty()) {
showEmptyView()
} else {
showContentView(offlineDevices)
}
})
}
private fun setUpQuickSearch() {
search.searchEdit
.textChanges()
.skipInitialValue()
.skip(1, TimeUnit.SECONDS)
.debounce(1, TimeUnit.SECONDS)
.observeOn(AndroidSchedulers.mainThread())
.subscribe({
offlineDevicesListAdapter.filter("$it")
}, {
offlineDevicesListAdapter.filter("")
})
.addTo(disposableBag)
}
private fun showEmptyView() {
recycler_view.gone()
empty_state_list_info.visible()
empty_list_state_image.visible()
updateResultCount(0)
}
private fun showContentView(offlineDevices: List<OssOfflineDevicesI>) {
empty_state_list_info.gone()
empty_list_state_image.gone()
offlineDevicesListAdapter.update(offlineDevices)
recycler_view.visible()
updateResultCount(offlineDevices.size)
}
private fun updateResultCount(resultCount: Int) {
search.countText.text = String.format("%s %d",
com.comarch.fsm.android.core.extensions.getString("total_results"), resultCount)
}
}
I wanted the seekbar value outside the onProgressChanged method use But it always gives me a value of zero. I want to take the value of two seekbars and multiply them
class BmiActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
var weight =0f
var height = 0f
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_bmi)
val seekbarHeight=findViewById<SeekBar>(R.id.seekBarHeight)
var tvResultHeight=findViewById<TextView>(R.id.textViewResultHeight)
val tvResultWeight=findViewById<TextView>(R.id.textViewResultWeight)
val seekbarWeight =findViewById<SeekBar>(R.id.seekBarWeight)
val spinnerAge=findViewById<Spinner>(R.id.spinnerAge)
val imageviewNeedle=findViewById<ImageView>(R.id.imageViewNeedle)
val tvResultBmi=findViewById<TextView>(R.id.textViewResultBmi)
seekbarHeight.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
tvResultHeight.text=" "+progress.toString()
height= progress.toFloat()
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
seekbarWeight.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
tvResultWeight.text=" "+progress.toString()
weight=progress.toFloat()
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
var result = weight/(height*height)
tvResultBmi.text=result.toString()
You can do callback/interface. And then when both triggered, the value changed.
First, you need to create interface. Create a new file named ResultInterface.kt
interface ResultInterface {
fun onValueChanged(height: Float, weight: Float)
}
And then put each of them to a function.
fun seekBarHeight(resultInterface: ResultInterface) {
seekbarHeight.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
tvResultHeight.text = " " + progress.toString()
val height = progress.toFloat()
resultInterface.onValueChanged(height, 0f)
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
}
fun seekBarWeight(resultInterface: ResultInterface) {
seekbarWeight.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(seekBar: SeekBar?, progress: Int, fromUser: Boolean) {
tvResultWeight.text = " " + progress.toString()
val weight = progress.toFloat()
resultInterface.onValueChanged(0f, weight)
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
}
Last, at your activity, implement the ResutInterface
class BmiActivity : AppCompatActivity(), ResultInterface {
After that you need to alt + enter . and the onValueChanged method will override.
override fun onValueChanged(height: Float, weight: Float) {
val result = weight/(height*height)
tvResultBmi.text=result.toString()
}
I have a viewPager with CubeTransformer, which is transforming every fragment. And inside every fragment is Image or Video view (with Exoplayer). And when you are trying to change a framgnet with transformation, exoplayer losses preview (I've got a black screen), even it's not playing. But after you changing condition to normal, preview is coming back
Ohterwise, if you will remove pageTransformer, review is not dissapears. How to keep preview always on screen?
CubeTransformer
class CubeTransformer : ViewPager.PageTransformer {
override fun transformPage(view: View, position: Float) {
if (view.visibility != View.VISIBLE) return
view.apply {
cameraDistance = (view.width * distanceMultiplier).toFloat()
pivotX = if (position < 0f) view.width.toFloat() else 0f
pivotY = view.height * 0.5f
rotationY = 90f * position
if (position < -1 || position > 1) {
alpha = 0f // item not visible
} else {
alpha = 1f
}
}
}
private companion object {
private const val distanceMultiplier: Int = 20
}
}
VideoView
class VideoView(context: Context) : ConstraintLayout(context, null) {
private val player = ExoPlayerFactory.newSimpleInstance(context, DefaultTrackSelector(), DefaultLoadControl())
private val dataSourceFactory = DefaultDataSourceFactory(context, "android")
private lateinit var model: Model
init {
inflate(context, R.layout.story_item_video, this)
video_view.player = player
video_view.keepScreenOn = true
video_view.setBackgroundColor(Color.TRANSPARENT)
video_view.setShutterBackgroundColor(Color.TRANSPARENT)
}
fun setData(model: Model?) {
if (model== null) return
this.model = model
val mediaSource = HlsMediaSource
.Factory(dataSourceFactory)
.setExtractorFactory(DefaultHlsExtractorFactory())
.createMediaSource(Uri.parse(model.streamLink))
player.playWhenReady = true
player.prepare(mediaSource)
player.addListener(object: Player.EventListener {
override fun onPlaybackParametersChanged(playbackParameters: PlaybackParameters?) {
}
override fun onSeekProcessed() {}
override fun onTracksChanged(trackGroups: TrackGroupArray?, trackSelections: TrackSelectionArray?) {
}
override fun onPlayerError(error: ExoPlaybackException?) {
}
override fun onLoadingChanged(isLoading: Boolean) {
}
override fun onPositionDiscontinuity(reason: Int) {
}
override fun onRepeatModeChanged(repeatMode: Int) {
}
override fun onShuffleModeEnabledChanged(shuffleModeEnabled: Boolean) {
}
override fun onTimelineChanged(timeline: Timeline?, manifest: Any?, reason: Int) {
}
override fun onPlayerStateChanged(playWhenReady: Boolean, playbackState: Int) {
}
})
}
}
After a day of searching, I've found an answer to my question. You just need to add app:surface_type="texture_view" to your PlayerView
I'm new here and this is my first post!
I try to learn Android app development and I'm stuck with this problem :
How can I update a textview inside a function? I code a small app which generates all the permutation with repetitions and write it in a textview.
It works, but the textview updates only at the end of all the permutations... Don't understand why...
Sorry if my English is bad, I'm French ;)
I try to use Thread, the app doesn't crash, it seems to work but the app goes directly in the background...
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
permutation2("abcdefgh", 8)
}
private fun permutation1(text: String, prefix: String, n: Int, k: Int): String {
if (k == 0) {
} else
for (i in 0..n) {
val newprefix = prefix + text[i]
if (newprefix.length >= text.length) {
zoneTexte.text = newprefix
}
permutation1(text, newprefix, n, k - 1)
}
return "Erreur"
}
private fun permutation2(text: String, k: Int) {
permutation1(text, "", text.length - 1, k)
}
}
Functions for permutations work well but the textview update only at the end (with the last permutation "hhhhhhhh") and I would like to update it for each permutation.
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
permutation2("abcdefgh", 8)
}
private fun permutation2(text: String, k: Int) {
MyCal().execute(text)
}
inner class MyCal : AsyncTask<String ,String, String>(){
override fun onProgressUpdate(vararg values: String?) {
super.onProgressUpdate(*values)
zoneTexte.text = values[0]
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
zoneTexte.text = result
}
override fun doInBackground(vararg p0: String?): String {
return permutation1(p0[0]!!, "", p0[0]!!.length?.minus(1), 8)
}
fun permutation1(text: String, prefix: String, n: Int, k: Int): String {
if (k == 0) {
} else
for (i in 0..n) {
val newprefix = prefix + text[i]
if (newprefix.length >= text.length) {
onProgressUpdate(newprefix)
return newprefix
}
permutation1(text, newprefix, n, k - 1)
}
return "Erreur"
}
}
}
onCreate is executed on the ui-thread, as is the case for permutation1() and permutation2(). The ui won't actually refresh until onCreate completes and ui can then refresh/redraw the screen, so that's why you don't see any incremental text updates until the end.
If you would like to see it update in real time, you may want to look into AsyncTask. In your particular example, you aren't really performing a long running task, so I'm not sure if you'll be able to see the incremental additions to your TextView even if you use AsyncTask.
After the help from Mark and Kishan I find the solution ! Thank you guys !
Here is the code :
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
permutation2("abcdefgh", 8)
}
private fun permutation2(text: String, k: Int) {
MyCal().execute(text)
}
inner class MyCal : AsyncTask<String ,String, String>(){
override fun onProgressUpdate(vararg values: String?) {
super.onProgressUpdate(*values)
runOnUiThread(Runnable { zoneTexte.text = values[0] })
}
override fun onPostExecute(result: String?) {
super.onPostExecute(result)
runOnUiThread(Runnable { zoneTexte.text = result })
}
override fun doInBackground(vararg p0: String?): String {
return permutation1(p0[0]!!, "", p0[0]!!.length?.minus(1), 8)
}
fun permutation1(text: String, prefix: String, n: Int, k: Int): String {
if (k == 0) {
} else
for (i in 0..n) {
val newprefix = prefix + text[i]
if (newprefix.length >= text.length) {
onProgressUpdate(newprefix)
return newprefix
}
permutation1(text, newprefix, n, k - 1)
}
return "Erreur"
}
}
}
I'm having this issue, with recyclerView, may you check two screenshots below:
So that's my issue, when onNotifyItemChange runs, other info are changed, incorrectlty. Now here goes my adapter:
class TimelineAdapter(var timeline: TimelineDTO,
var toggleLikeClicked: OnRowClick,
var onCommentClicked: OnRowClick,
var onMediaClick: OnRowClick,
val onUserClicked: OnRowClick,
val reportPost: OnRowClick,
val editPost : OnRowClick,
val deletePost: OnRowClick,
val contract: TimelineViewContract) : BaseAdapter<RecyclerView.ViewHolder>() {
init {
setHasStableIds(true)
}
private var currentItem: Int = 0
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
when (PostType.fromInt(viewType)) {
PostType.BASIC -> {
return PostViewHolder(parent.inflate(R.layout.row_post_default_item),
toggleLikeClicked, onCommentClicked, onMediaClick,
onUserClicked, reportPost,
editPost,
deletePost,
FirebaseAnalytics.getInstance(contract.returnContext()))
}
PostType.NEXT_TALKS -> {
return PostNextTalksViewHolder(parent.inflate(R.layout.row_post_next_talks_item),
contract)
}
else -> {
if(!BuildConfig.DEBUG) {
Crashlytics.log("Should not come here")
}
logE("adapter else!!")
return PostViewHolder(parent.inflate(R.layout.row_post_default_item),
toggleLikeClicked, onCommentClicked, onMediaClick,
onUserClicked, reportPost,
editPost,
deletePost,
FirebaseAnalytics.getInstance(contract.returnContext()))
}
}
}
override fun getItemCount(): Int {
var count = timeline.posts.size
if(hasValue(timeline.nextTalks.size)){
count++
}
return count
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
currentItem = position
val alignedPositon = getAlignedPosition(position)
when (holder) {
is PostViewHolder -> holder.bind(timeline.posts[alignedPositon])
is PostNextTalksViewHolder -> {
holder.bind(timeline.nextTalks)
}
is PostCarousselViewHolder -> {
holder.bind(ArrayList<String>())
}
}
}
fun getPostAt(position: Int): PostDTO {
val post: PostDTO
val alignedPositon = getAlignedPosition(position)
post = timeline.posts[alignedPositon]
return post
}
override fun getItemId(position: Int): Long {
val aligned = getAlignedPosition(position)
return aligned.toLong()
}
private fun getAlignedPosition(position: Int): Int {
var alignedPositon = position
if (hasValue(timeline.nextTalks.size)){
alignedPositon--
}
return alignedPositon
}
override fun getItemViewType(position: Int): Int {
val hasPinned = timeline.posts.any { it.postType == PostType.PINNED.id }
if(hasPinned) {
if(position == 1 && timeline.nextTalks.any()){
return PostType.NEXT_TALKS.id
}
}
else {
if(position == 0 && timeline.nextTalks.any()){
return PostType.NEXT_TALKS.id
}
}
return timeline.posts[getAlignedPosition(position)].postType
}
fun updateItemAt(postLocal: PostLocal, commentIndexPost: Int) {
timeline.posts.removeAt(commentIndexPost)
timeline.posts.add(commentIndexPost, PostDTO(postLocal))
notifyItemChanged(commentIndexPost)
}
fun addItems(newPosts: TimelineDTO) {
timeline.posts.addAll(newPosts.posts)
timeline.nextTalks.addAll(newPosts.nextTalks)
notifyItemRangeInserted(itemCount, newPosts.posts.size)
}
fun resetItems(nextPosts: TimelineDTO) {
timeline.posts.clear()
timeline.nextTalks.clear()
timeline.posts.addAll(nextPosts.posts)
timeline.nextTalks.addAll(nextPosts.nextTalks)
notifyDataSetChanged()
}
fun removeAt(position: Int) {
timeline.posts.removeAt(position)
notifyItemRemoved(position)
notifyItemRangeChanged(position, timeline.posts.size)
}
}
Using notifyItemChanged() might trigger "fading in and out" effect which is not necessarily desired (unless You use stable IDs or killed change animation in animator).
If You know what was changed in an item, it's better to use an update payload (see an example here) to partially update your ViewHolders without triggering full rebind.
Otherwise if list is relatively small and You don't know what changed, you can also use DiffUtil to help generate list of changes/change payloads "semi-automatically".