android beginner here. any help is much appreciated .
I am working on an app that can do a simple experiment.
the app displays images and asks users to rate it from 1 to 10.
I have 1 activity and two layouts experiment begins.
I have two layouts merged under FrameLayout.
what I want to achieve is :
'====>start experiment >show first image for 10 seconds >change layout to ratings layout>after user selects rating>loopback with different image>finish() when imagelist is empty. '
here is what I tried
I have tried viewflipper but shownext() and showprevious() methods dont update values.
now i am trying using layout visibility ,showing and hiding the layouts
class Presenter : AppCompatActivity() {
//val currentTime = Calendar.getInstance().time
private lateinit var binding: ActivityPresenterBinding
lateinit var layout1:View
lateinit var layout2:View
val imgList=Constants.getImages()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
//setContentView(R.layout.activity_presenter)
binding = ActivityPresenterBinding.inflate(layoutInflater)
setContentView(binding.root)
layout1 = binding.imageView
layout2=binding.ratingView
startSlider()
}
private fun startSlider() {
Handler(Looper.getMainLooper()).apply {
//arr.shuffle()
var index = 0
var imageView = binding.imgPresenter
val runnable = object : Runnable {
override fun run() {
imageView.setImageResource(imgList[index].image)
layout1.visibility= View.VISIBLE
Log.i("number ","${index}")
postDelayed(this, 5000)
index++
layout1.visibility=View.GONE
layout2.visibility=View.VISIBLE
binding.sbSeekbar.setOnSeekBarChangeListener(object : SeekBar.OnSeekBarChangeListener{
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
Toast.makeText(applicationContext, "$p1", Toast.LENGTH_LONG).show()
//save rating (1-10)
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
}
})
}
}
postDelayed(runnable, 1000)
}
}
here my layout file
<FrameLayout android:id="#+id/viewFliper"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/imageView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<ImageView
android:id="#+id/img_presenter"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic_bg"
/>
</LinearLayout>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/ratingView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:padding="16dp"
>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="how do you feel about this image from one to 10"
android:orientation="vertical"
android:gravity="center"
android:layout_marginBottom="20dp"
/>
<SeekBar
android:id="#+id/sb_seekbar"
style="#style/Widget.AppCompat.SeekBar.Discrete"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:max="10"
android:paddingStart="6dp"
android:paddingEnd="6dp"
android:progress="3"
android:stepSize="1" />
</LinearLayout>
this is not hiding the views after the second image
what am I doing wrong?
try this and apply viewbinding
lateinit var runnable: Runnable
private fun startSlider() {
Handler(Looper.getMainLooper()).apply {
var flag = 0
var index = 0
runnable = Runnable {
if (flag == 0) {
img_presenter.setImageResource(imgList[index])
layout1.visibility = View.VISIBLE
layout2.visibility = View.GONE
postDelayed(runnable, 5000)
flag = 1
index++
} else {
layout1.visibility = View.GONE
layout2.visibility = View.VISIBLE
sb_seekbar.setOnSeekBarChangeListener(object :
SeekBar.OnSeekBarChangeListener {
override fun onProgressChanged(p0: SeekBar?, p1: Int, p2: Boolean) {
// Toast.makeText(applicationContext, "$p1", Toast.LENGTH_LONG).show()
//save rating (1-10)
}
override fun onStartTrackingTouch(p0: SeekBar?) {
}
override fun onStopTrackingTouch(p0: SeekBar?) {
index++
flag = 0
postDelayed(runnable, 1000)
}
})
}
}
postDelayed(runnable, 1000)
}
}
Related
I am new to Android TV apps development.
My issue is I have one or more of app's screens cut off from the right when open the side menu.
I tried going through Google's Android TV Documentation but couldn't find a clue on it.
Here you can see attached image.
Here is my code for show/hide side menu for my TV app:
private fun showSideMenu() {
val sideMenuWidth = mSideMenuView.width
mSideMenuAnimator = ObjectAnimator.ofFloat(mSideMenuView, "translationX", 0f)
mSideMenuAnimator?.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) {
mSideMenuAnimator = null
mSideMenuView.visibility = View.VISIBLE
hideMenuText()
mSideMenuView.requestFocus()
mContainer.clearFocus()
}
override fun onAnimationEnd(animation: Animator?) {
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
}
})
mSideMenuAnimator?.duration = SIDE_MENU_ANIMATION_DURATION_MILLIS
val containerAnimator = ObjectAnimator.ofFloat(mContainer, "translationX", sideMenuWidth * 1f)
containerAnimator.duration = SIDE_MENU_ANIMATION_DURATION_MILLIS
val animatorSet = AnimatorSet()
animatorSet.play(mSideMenuAnimator).with(containerAnimator)
animatorSet.start()
}
private fun hideSideMenu() {
val sideMenuWidth = mSideMenuView.width
mSideMenuAnimator = ObjectAnimator.ofFloat(mSideMenuView, "translationX", -sideMenuWidth * 1f)
mSideMenuAnimator?.addListener(object : Animator.AnimatorListener {
override fun onAnimationStart(animation: Animator?) {
mSideMenuView.clearFocus()
mContainer.requestFocus()
}
override fun onAnimationEnd(animation: Animator?) {
mSideMenuAnimator = null
mSideMenuView.visibility = View.INVISIBLE
// Give focus control to current fragment
mCurrentFragment?.onReceiveFocus()
showMenuText()
}
override fun onAnimationRepeat(animation: Animator?) {
}
override fun onAnimationCancel(animation: Animator?) {
}
})
mSideMenuAnimator?.duration = SIDE_MENU_ANIMATION_DURATION_MILLIS
val containerAnimator = ObjectAnimator.ofFloat(mContainer, "translationX", 0f)
containerAnimator.duration = SIDE_MENU_ANIMATION_DURATION_MILLIS
val animatorSet = AnimatorSet()
animatorSet.play(mSideMenuAnimator).with(containerAnimator)
animatorSet.start()
}
Here is my design for the side menu:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:keepScreenOn="true">
<com.myapp.widget.SideMenuView
android:id="#+id/view_side_menu"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:translationX="-220dp"
android:visibility="invisible" />
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:id="#+id/text_menu"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentEnd="true"
android:layout_alignParentTop="true"
android:layout_marginEnd="25dp"
android:layout_marginTop="25dp"
android:drawablePadding="4dp"
android:background="#drawable/background_side_menu_indicator"
android:drawableEnd="#drawable/icon_side_menu"
android:focusable="false"
android:text="MENU"
app:primaryForegroundColor="false"
style="#style/Text.SideMenuIndicator"
tools:ignore="RelativeOverlap" />
I would appreciate any clue about this issue.
I want to add a headerview that hides when user scrolls to down and shows again when user scrolls to up.
Example: https://imgur.com/a/tTq70B0
As you can see in the link "You are writing as..." pharase is showing only when user scrolls to top. Is there something like that in Android sdk?
How can i achive the same thing?
Obtaining the scroll event is just the first step to achieving this. Animations is required to achieve the effect. I recreated a simple version of the gif example you posted.
Layout for the main activity, activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:animateLayoutChanges="true"> <!-- Note the last line-->
<TextView
android:id="#+id/textview_hello"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_margin="8dp"
android:text="Hello Stack Overflow!"/>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/recyclerview_main"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Below is the code for the main activity where we populate the RecyclerView and use the addOnScrollListener to provide animations to the TextView. Do note the commented out lines these will provide a default fade-out or fade-in animation due to the noted line in the xml layout above. The method slideAnimation() is an example of creating a custom animation. This link proved useful for creating the animations.
class MainActivity : AppCompatActivity() {
private lateinit var viewAdapter: RecyclerView.Adapter<*>
private lateinit var viewManager: LinearLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// Some data for the RecyclerView
val data: List<String> = (1..100).toList().map { it.toString() }
viewManager = LinearLayoutManager(this)
viewAdapter = TextAdapter(data)
findViewById<RecyclerView>(R.id.recyclerview_main).apply {
setHasFixedSize(true)
layoutManager = viewManager
adapter = viewAdapter
addOnScrollListener(
object : RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
val pastVisibleItems = viewManager.findFirstCompletelyVisibleItemPosition()
if (pastVisibleItems == 0) {
slideAnimation(0f, 1f, View.VISIBLE)
//textview_hello.visibility = View.VISIBLE
} else if (textview_hello.visibility != View.GONE) {
slideAnimation(-150f, 0f, View.GONE)
//textview_hello.visibility = View.GONE
}
}
}
)
}
... // SlideAnimation function
}
}
The slideAnimation function
private fun slideAnimation(translationY: Float, alpha: Float, viewVisibility: Int) {
textview_hello.visibility = View.VISIBLE
textview_hello.clearAnimation()
textview_hello
.animate()
.translationY(translationY)
.alpha(alpha)
.setListener(object : AnimatorListenerAdapter() {
override fun onAnimationEnd(animation: Animator) {
super.onAnimationEnd(animation)
textview_hello.clearAnimation()
textview_hello.visibility = viewVisibility
}
})
.duration = 500
}
The adapter for the RecycleView:
class TextAdapter(private val textList: List<String>) :
RecyclerView.Adapter<TextAdapter.TextViewHolder>() {
class TextViewHolder(val textView: TextView) : RecyclerView.ViewHolder(textView)
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): TextViewHolder {
val textView = LayoutInflater.from(parent.context)
.inflate(R.layout.item_text_view, parent, false) as TextView
return TextViewHolder(textView)
}
override fun onBindViewHolder(holder: TextViewHolder, position: Int) {
holder.textView.text = textList[position]
}
override fun getItemCount() = textList.size
}
Item to display in the RecyclerView, item_text_view.xml
<?xml version="1.0" encoding="utf-8"?>
<TextView xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="wrap_content"
android:layout_margin="8dp"
android:padding="16dp"
android:textAlignment="center"
android:background="#android:color/darker_gray">
</TextView>
While working with Kotlin, in my BaseActivity I want to implement showProgressBar i.e,
abstract class BaseActivity : AppCompatActivity() {
var progressBar: ProgressBar? = null
fun showProgressBar() {
progressBar = ProgressBar(this, null, android.R.attr.progressBarStyleSmall)
val params = RelativeLayout.LayoutParams(120, 120)
params.addRule(RelativeLayout.CENTER_IN_PARENT)
val layout = this.findViewById<ViewGroup>(android.R.id.content)
layout.addView(progressBar, params)
}
fun hideProgressBar() {
progressBar?.visibility = GONE
}
}
MainActivity layout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".activities.MainActivity">
<TextView
android:id="#+id/textview"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World!"
android:layout_centerInParent="true" />
</RelativeLayout>
I am calling from MainActivity like,
class MainActivity : BaseActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
Log.i(TAG, "calling showProgressBar")
showProgressBar()
Handler(Looper.getMainLooper()).postDelayed(Runnable {
Log.i(TAG, "calling hideProgressBar")
hideProgressBar()
}, 5000)
}
}
But params.addRule(RelativeLayout.CENTER_IN_PARENT) seem does not work. Output is in below screenshot. How can I move the progressBar in centre of the screen?
In MainActivity, I have a pie chart, where the libary get from GitHub - PhilJay/MPAndroidChart: A powerful Android chart view. I add the pie chart into cardView.When cardView is clicked, toast suppose to be displayed. But the onClickListener not working at all.
MainActivity
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
showChart()
cardView.setOnClickListener {
Toast.makeText(application,"clicked",Toast.LENGTH_LONG).show()
}
}
private fun showChart() {
chart.setUsePercentValues(true)
chart.description.isEnabled = false
chart.center
chart.extraRightOffset = 20f
chart.isDrawHoleEnabled = true
chart.setHoleColor(Color.WHITE)
chart.setTransparentCircleColor(Color.WHITE)
chart.setTransparentCircleAlpha(10)
chart.holeRadius = 58f
chart.transparentCircleRadius = 46f
chart.setDrawCenterText(true)
chart.rotationAngle = 0f
chart.isRotationEnabled = true
chart.animateY(1400, Easing.EaseInOutQuad)
val l = chart.legend
l.verticalAlignment = Legend.LegendVerticalAlignment.CENTER
l.horizontalAlignment = Legend.LegendHorizontalAlignment.LEFT
l.orientation = Legend.LegendOrientation.VERTICAL
l.setDrawInside(false)
l.xOffset = 50f
chart.setEntryLabelColor(Color.WHITE)
chart.setEntryLabelTextSize(12f)
setData(3,5)
}
private fun setData(numOpen: Int, numInProgress: Int) {
val entries = ArrayList<PieEntry>()
val colors = ArrayList<Int>()
if (numOpen > 0) {
entries.add(PieEntry(numOpen.toFloat(), "Open"))
colors.add(ColorTemplate.rgb("#F44336"))
}
if (numInProgress > 0) {
entries.add(PieEntry(numInProgress.toFloat(), "Progress"))
colors.add(ColorTemplate.rgb("#2196F3"))
}
val dataSet = PieDataSet(entries, "Status")
dataSet.sliceSpace = 3f
dataSet.iconsOffset = MPPointF(0f, 40f)
dataSet.selectionShift = 5f
dataSet.colors = colors
val data = PieData(dataSet)
data.setValueFormatter(PercentFormatter(chart))
data.setValueTextSize(11f)
data.setValueTextColor(Color.WHITE)
chart.data = data
// undo all highlights
chart.highlightValues(null)
chart.invalidate()
}
}
main_activity
<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.CardView
android:id="#+id/cardView"
android:clickable="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="15dp"
android:layout_marginTop="15dp"
android:layout_marginRight="15dp">
<com.github.mikephil.charting.charts.PieChart
android:background="#color/colorPrimary"
android:id="#+id/chart"
android:layout_width="match_parent"
android:layout_height="250dp"
android:layout_gravity="center_horizontal|center_vertical"/>
</android.support.v7.widget.CardView>
</LinearLayout>
</ScrollView>
Image
As the PieChart fully absorbing the click to interact with the chart elements, the click listener defined in the parent will not be called. Even If you set an OnClickListener to PieChart, it won't work. The solution to this problem is to set onChartGestureListener to PieChart and call your method from onChartSingleTapped.
Example
override fun onCreate(savedInstanceState: Bundle?) {
...
cardView.setOnClickListener {
doThis();
}
chart.onChartGestureListener = object : OnChartGestureListener {
override fun onChartSingleTapped(me: MotionEvent?) {
doThis()
}
}
}
fun doThis(){
// your code goes here
}
I'm struggling with glide loading custom item layout with groupie. Being particular - on item bind when I use glide to load images (images are ~12kb). Experiencing a "frozen frame". Profiler shows big CPU usage jump on the moment when glide loads images. It lags even if I add 3 items at a time but I need to add more (there is not much difference in cpu usage between 3 and 48 items so it freezes for about the same time). Tested with loading it from Resources/Precached/Direct download, with and without RequestOptions() - everything is the same
Some code related to the issue:
HomeScreen.kt
var subscription = 0
//Transformation
var loading = false
var itemWidth = 120
class HomeScreen : AppCompatActivity() {
val categoriesReference = FirebaseDatabase.getInstance().getReference("/categories")
var photos = ArrayList<PhotoItem>()
val adapter = GroupAdapter<ViewHolder>()
var itemsAllowed = 48
lateinit var manager: GridLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_home_screen)
itemWidth = getItemWidth(this#HomeScreen)
setSupportActionBar(toolbar)
window.exitTransition = null
//Action bar options
supportActionBar?.setDisplayShowHomeEnabled(true)
supportActionBar?.title = "Все обои"
//FIX BLINKING ON TRANSITIONS
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
/*var fade = Fade()
fade.excludeTarget(toolbar, true)
fade.excludeTarget(toolbar2, true)
fade.excludeTarget(android.R.id.statusBarBackground, true);
fade.excludeTarget(android.R.id.navigationBarBackground, true);
getWindow().setEnterTransition(fade)
getWindow().setExitTransition(fade)*/
}
window.decorView.systemUiVisibility = (View.SYSTEM_UI_FLAG_LAYOUT_STABLE
or View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
or View.SYSTEM_UI_FLAG_FULLSCREEN)
//Working with layout
manager = GridLayoutManager(this, calculateNoOfColumns(this#HomeScreen))
adapter.setHasStableIds(true)
recycleView.isNestedScrollingEnabled = false
recycleView.adapter = adapter
recycleView.layoutManager = manager
loadPageFully()
addItemsToMenu()
//Listener for navigation view
navigView.setNavigationItemSelectedListener {
/*if (it.toString() == "Купить тариф") {
subscription = 1
alert("Тариф успешно установлен") {
navigView.menu.clear()
addItemsToMenu()
loadPageFully()
yesButton { }
supportActionBar?.title = "Все обои"
}.show()
true
} else {*/
when(it.title.toString()){
"Все обои" -> {
loadPageFully()
}
}
drawerLayoutMain.closeDrawer(GravityCompat.START, true)
for (i in 0 until navigView.menu.size()) {
navigView.menu.getItem(i).setChecked(false)
}
it.setChecked(true)
loadPageFully(it.toString())
loadingImageView.visibility = View.GONE
waveImageView.visibility = View.GONE
supportActionBar?.title = it.toString()
true
// }
}
//Shuffle images in layout manager
shuffleButton.onClick {
photos.shuffle()
adapter.clear()
photos.forEach {
if (manager.itemCount < itemsAllowed) {
adapter.add(it)
}
}
}
scrollView3.setOnScrollChangeListener(object : View.OnScrollChangeListener {
override fun onScrollChange(v: View?, scrollX: Int, scrollY: Int, oldScrollX: Int, oldScrollY: Int) {
println(loading.toString())
if (!loading && !scrollView3.canScrollVertically(1) && manager.itemCount > 0) {
loading = true
if (itemsAllowed == photos.size) {
} else if (itemsAllowed + 48 >= photos.size) {
for (i in 48.downTo(0)) {
if (itemsAllowed + i == photos.size) {
itemsAllowed += i
waveImageView.visibility = View.VISIBLE
doAsync {
Thread.sleep(300)
scrollView3.fullScroll(View.FOCUS_DOWN)
}
}
}
} else {
waveImageView.visibility = View.VISIBLE
doAsync {
Thread.sleep(300)
scrollView3.fullScroll(View.FOCUS_DOWN)
}
itemsAllowed += 48
}
checkOk()
}
}
})
recycleView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) {
super.onScrollStateChanged(recyclerView, newState)
when (newState) {
SCROLL_STATE_IDLE -> Glide.with(this#HomeScreen).resumeRequests()
SCROLL_STATE_TOUCH_SCROLL, SCROLL_STATE_FLING -> Glide.with(this#HomeScreen).pauseRequests()
}
}
})
}
//On home button clicked
override fun onOptionsItemSelected(item: MenuItem): Boolean {
return when (item.itemId) {
android.R.id.home -> {
drawerLayoutMain.openDrawer(GravityCompat.START)
true
}
else -> super.onOptionsItemSelected(item)
}
}
fun getEntries(categoryName: String = "All") {
//This fun with ChildEventListeners(Firebase SDK) gets urls and pushes them to photos no problem here because by the time lags occur they all are in photos.
}
var okToLoad = false
var loaded = 0
fun loadImages() {
if (okToLoad) {
okToLoad = false
if (photos.size < itemsAllowed) {
itemsAllowed = photos.size
}
loading = true
try {
for (i in manager.findLastVisibleItemPosition() + 1 until itemsAllowed) {
Glide.with(this#HomeScreen).load(photos[i].url).apply(
RequestOptions().diskCacheStrategy(
DiskCacheStrategy.ALL
)/*.skipMemoryCache(true)*/
).apply(RequestOptions().dontTransform()/*.override(220, 330)*/)
.listener(object : RequestListener<Drawable> {
override fun onResourceReady(
resource: Drawable?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Drawable>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
loaded += 1
println("1:$loaded")
println("2:$itemsAllowed")
if (loaded == itemsAllowed) {
Timer().schedule(object : TimerTask() {
override fun run() {
runOnUiThread {
waveImageView.visibility = View.GONE
shuffleButton.visibility = View.VISIBLE
okToLoad = true
loading = false
loadingImageView.visibility = View.GONE
for (i in manager.findLastVisibleItemPosition() + 1 until loaded) {
adapter.add(photos[i])
}
}
}
}, 1000)
}
return false
}
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Drawable>?,
isFirstResource: Boolean
): Boolean {
return false
}
}).preload(220, 330)
}
} catch (e: IndexOutOfBoundsException) {
} catch (e: FileNotFoundException) {
Toast.makeText(this#HomeScreen, "Квота превышена", Toast.LENGTH_LONG).show()
}
}
}
fun checkOk() {
doAsync {
if (photos.size == 0) {
okToLoad = false
Thread.sleep(100)
checkOk()
} else {
okToLoad = true
uiThread {
loadImages()
}
}
}
}
fun addItemsToMenu() {
categoriesReference.addChildEventListener(object : ChildEventListener {
override fun onChildAdded(p0: DataSnapshot, p1: String?) {
navigView.menu.add(p0.key.toString()).setIcon(R.drawable.ic_bookmark_black_24dp)
}
override fun onCancelled(p0: DatabaseError) = Unit
override fun onChildChanged(p0: DataSnapshot, p1: String?) = Unit
override fun onChildMoved(p0: DataSnapshot, p1: String?) = Unit
override fun onChildRemoved(p0: DataSnapshot) = Unit
})
}
fun loadPageFully(key: String = "All") {
shuffleButton.visibility = View.GONE
loaded = 0
okToLoad = false
loadingImageView.visibility = View.VISIBLE
doAsync {
Glide.get(this#HomeScreen).clearDiskCache()
}
Glide.get(this#HomeScreen).clearMemory()
manager.removeAndRecycleAllViews(recycleView.Recycler())
adapter.clear()
photos.clear()
getEntries(key)
checkOk()
}
fun calculateNoOfColumns(context: Context): Int {
val displayMetrics = context.getResources().getDisplayMetrics();
val dpWidth = displayMetrics.widthPixels / displayMetrics.density;
val scalingFactor = 110 // You can vary the value held by the scalingFactor
// variable. The smaller it is the more no. of columns you can display, and the
// larger the value the less no. of columns will be calculated. It is the scaling
// factor to tweak to your needs.
var columnCount = (dpWidth / scalingFactor).toInt()
if (columnCount < 3) columnCount = 3
return columnCount // if column no. is less than 2, we still display 2 columns
}
fun getItemWidth(context: Context): Int {
val displayMetrics = context.resources.displayMetrics
val dpWidth = displayMetrics.widthPixels
return (dpWidth / calculateNoOfColumns(context)).toInt()
}
}
val factory = DrawableCrossFadeFactory.Builder().setCrossFadeEnabled(true).build()
//Layout item for adapter
class PhotoItem(
val cnt: Context,
var url: String,
var downloads: Int,
var ref: DatabaseReference,
var locked: Boolean
) : Item<ViewHolder>() {
override fun bind(viewHolder: ViewHolder, position: Int) {
viewHolder.itemView.itemImageView.layoutParams.width = itemWidth
viewHolder.itemView.itemImageView.layoutParams.height = itemWidth
Glide.with(cnt)
.load(url)
.apply(RequestOptions().placeholder(R.drawable.placeholder).format(DecodeFormat.PREFER_RGB_565))/*transition(DrawableTransitionOptions.withCrossFade(factory)).apply(RequestOptions().placeholder(R.drawable.background))*//**//*.skipMemoryCache(true)*//**//*priority(Priority.HIGH))*//**//*.listener(
object : RequestListener<Bitmap> {
override fun onLoadFailed(
e: GlideException?,
model: Any?,
target: com.bumptech.glide.request.target.Target<Bitmap>?,
isFirstResource: Boolean
): Boolean {
return false
}
override fun onResourceReady(
resource: Bitmap?,
model: Any?,
target: Target<Bitmap>?,
dataSource: DataSource?,
isFirstResource: Boolean
): Boolean {
return false
}
})*/.into(viewHolder.itemView.itemImageView)
viewHolder.itemView.itemImageView.transitionName = url
viewHolder.itemView.setOnClickListener {
var intent = Intent(cnt, PhotoScreen::class.java).apply {
putExtra("url", url)
putExtra("ref", ref.toString())
putExtra("downs", downloads.toString())
putExtra("locked", locked.toString())
}
val options = ActivityOptionsCompat.makeSceneTransitionAnimation(
cnt as AppCompatActivity,
viewHolder.itemView.itemImageView,
viewHolder.itemView.itemImageView.transitionName
)
cnt.startActivity(intent, options.toBundle())
}
}
override fun getLayout(): Int {
return R.layout.image_item
}
Home
<?xml version="1.0" encoding="utf-8"?>
<androidx.drawerlayout.widget.DrawerLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="#+id/drawerLayoutMain"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".HomeScreen"
android:background="#drawable/background">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent" android:id="#+id/relativeLayout"
>
<androidx.core.widget.NestedScrollView
android:layout_width="0dp"
android:layout_height="0dp"
tools:layout_conversion_absoluteHeight="598dp"
tools:layout_conversion_absoluteWidth="384dp" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toBottomOf="#+id/toolbar"
android:id="#+id/scrollView3"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintBottom_toBottomOf="parent"
android:overScrollMode="ifContentScrolls"
android:fillViewport="false">
<LinearLayout android:layout_width="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:id="#+id/linearLayout"
android:descendantFocusability="blocksDescendants"
android:layout_marginLeft="0dp" android:layout_marginRight="0dp"
android:layout_gravity="fill">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="wrap_content"
android:layout_height="-100dp"
android:layout_marginTop="0dp" android:id="#+id/recycleView"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
android:layout_marginRight="0dp"
android:focusableInTouchMode="true"
android:scrollbars="vertical"
android:layout_gravity="center_horizontal|fill"
>
</androidx.recyclerview.widget.RecyclerView>
<pl.droidsonroids.gif.GifImageView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/waveImageView" android:src="#drawable/intro_image"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:visibility="gone" android:background="#drawable/background"/>
</LinearLayout>
</androidx.core.widget.NestedScrollView>
<androidx.appcompat.widget.Toolbar android:id="#+id/toolbar" android:layout_width="0dp"
android:layout_height="45dp"
android:background="#drawable/background"
app:titleTextColor="#android:color/white"
android:textAlignment="gravity"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:isScrollContainer="false"
android:fitsSystemWindows="false"
tools:layout_conversion_absoluteHeight="42dp"
tools:layout_conversion_absoluteWidth="384dp"
app:layout_constraintTop_toTopOf="parent"
app:navigationIcon="#drawable/ic_list_black_24dp">
</androidx.appcompat.widget.Toolbar>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content" app:srcCompat="#drawable/ic_shuffle_black_24dp"
android:id="#+id/shuffleButton"
app:layout_constraintTop_toTopOf="parent" app:layout_constraintEnd_toEndOf="#+id/toolbar"
android:padding="10dp"
app:layout_constraintBottom_toTopOf="#+id/scrollView3"
android:focusedByDefault="true"
/>
<pl.droidsonroids.gif.GifImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/loadingImageView" android:visibility="visible"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" android:layout_marginBottom="8dp"
app:layout_constraintBottom_toBottomOf="parent" android:layout_marginTop="8dp"
app:layout_constraintTop_toTopOf="parent" android:src="#drawable/placeholder_gif"/>
</androidx.constraintlayout.widget.ConstraintLayout>
<com.google.android.material.navigation.NavigationView
android:layout_width="250dp"
android:layout_height="match_parent"
android:layout_gravity="start"
app:headerLayout="#layout/header_menu"
android:theme="#style/ThemeOverlay.AppCompat.ActionBar" android:id="#+id/navigView"
app:itemBackground="#drawable/menu_item_background"
android:background="#drawable/menu_bitmap"/>
</androidx.drawerlayout.widget.DrawerLayout>
ImageItem layout
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<ImageView
android:layout_width="110dp"
android:layout_height="110dp"
android:id="#+id/itemImageView"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintTop_toTopOf="parent"
android:scaleType="centerCrop"/>
</FrameLayout>
OnMeasure() and nativePollOnce() methods takes a lot as I see. Still, don't know what to do with it
Solved it
The main problem was that groupie adapter as for now makes diffs on UI thread. And that caused lags. Switching to another library may help you. I've switched to Epoxy by airbnb
P.S. I had nested recyclerview in scrollview. Removing scrollview added more performance