How to display a text view on CameraX preview view? - android

I want to display a text view in the preview view of camera. It will appear like a label on the camera preview. It should not affect the image. Just appear like a label on preview view. I tried using frame layout but the text view disappears on the preview view
Here's my 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:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000000"
android:fitsSystemWindows="true"
tools:context=".MainActivity">
<Button
android:id="#+id/camera_capture_button"
android:layout_width="60dp"
android:layout_height="60dp"
android:background="#drawable/ic_baseline_camera_24"
android:elevation="2dp"
android:layout_marginBottom="20dp"
android:scaleType="fitCenter"
android:layout_gravity="bottom|center"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="0.498"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.926" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Hello"
android:textSize="25dp" />
<androidx.camera.view.PreviewView
android:id="#+id/viewFinder"
android:layout_width="379dp"
android:layout_height="576dp"
android:layout_gravity="center_horizontal"
android:layout_marginTop="20dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent">
</androidx.camera.view.PreviewView>
</FrameLayout>
Main Activity
Here's the main logic->
package com.arpit.cameraxdemo
import android.Manifest
import android.content.pm.PackageManager
import android.os.Bundle
import android.util.Log
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.camera.core.CameraSelector
import androidx.camera.core.ImageCapture
import androidx.camera.core.Preview
import androidx.camera.lifecycle.ProcessCameraProvider
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import kotlinx.android.synthetic.main.activity_main.*
import java.util.concurrent.ExecutorService
import java.util.concurrent.Executors
class MainActivity : AppCompatActivity() {
private var imageCapture: ImageCapture? = null
private lateinit var cameraExecutor: ExecutorService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
supportActionBar?.hide()
if (allPermissionsGranted()) {
startCamera()
} else {
ActivityCompat.requestPermissions(this, REQUIRED_PERMISSIONS, REQUEST_CODE_PERMISSIONS)
}
camera_capture_button.setOnClickListener {
takePhoto()
}
cameraExecutor = Executors.newSingleThreadExecutor()
}
private fun takePhoto() {
}
private fun startCamera() {
val cameraProviderFuture = ProcessCameraProvider.getInstance(this)
cameraProviderFuture.addListener({
val cameraProvider: ProcessCameraProvider = cameraProviderFuture.get()
val preview = Preview.Builder()
.build()
.also {
it.setSurfaceProvider(viewFinder.surfaceProvider)
}
imageCapture = ImageCapture.Builder().build()
val cameraSelector = CameraSelector.DEFAULT_BACK_CAMERA
try {
cameraProvider.unbindAll()
cameraProvider.bindToLifecycle(
this, cameraSelector, preview, imageCapture
)
} catch (exc: Exception) {
Log.e(TAG, "Use case binding failed", exc)
}
}, ContextCompat.getMainExecutor(this))
}
private fun allPermissionsGranted() = REQUIRED_PERMISSIONS.all {
ContextCompat.checkSelfPermission(baseContext, it) == PackageManager.PERMISSION_GRANTED
}
// checks the camera permission
override fun onRequestPermissionsResult(
requestCode: Int, permissions: Array<String>, grantResults:
IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if (requestCode == REQUEST_CODE_PERMISSIONS) {
if (allPermissionsGranted()) {
startCamera()
} else {
Toast.makeText(this, "Permissions not granted by the user.", Toast.LENGTH_SHORT).show()
finish()
}
}
}
companion object {
private const val TAG = "CameraXGFG"
private const val REQUEST_CODE_PERMISSIONS = 20
private val REQUIRED_PERMISSIONS = arrayOf(Manifest.permission.CAMERA)
}
override fun onDestroy() {
super.onDestroy()
cameraExecutor.shutdown()
}
}

Try below code with RelativeLayout
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
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">
<androidx.camera.view.PreviewView
android:id="#+id/previewView"
android:layout_width="match_parent"
android:layout_height="match_parent" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:gravity="center"
android:text="CameraX" />
<Button
android:id="#+id/imageCaptureBtn"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_margin="10dp"
android:gravity="center"
android:text="Click Image" />
</RelativeLayout>

Thanks for your help everyone. I have found the answer to my question. Actually what I was looking for is called overlay
viewFinder.overlay.add(tvText)

use the element "elevation" with 2dp

Related

Floating Action Button not visible over Mapbox Android

It has been a while since I have developed an Android app. So current dev work is pretty new for me. I am trying to create a Mapbox Android API based app. So far I have successfully loaded User location and move camera based on location change; however, the FAB I have added on the layout is not showing up in either emulator or my phone. It is visible in the XML design view. I believe it might be due to the setContentView(mapView) in MapsActivity.kt which I don't know how is it not able to load the whole layout. Am I missing anything?
activity_maps.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:mapbox="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.mapbox.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="40.7128"
mapbox:mapbox_cameraTargetLng="-74.0060"
mapbox:mapbox_cameraZoom="9.0">
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:backgroundTint="#color/purple_200"
android:layout_margin="16dp"
android:contentDescription="#string/fab_description"
android:src="#drawable/ic_plus_icon"
tools:ignore="ImageContrastCheck" />
</com.mapbox.maps.MapView>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
MapsActivity.kt
package com.example.pinpoint
import android.Manifest
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import androidx.core.app.ActivityCompat
import com.example.pinpoint.com.example.pinpoint.LocationInitHelper
import com.example.pinpoint.com.example.pinpoint.LocationListeningCallback
import com.example.pinpoint.databinding.ActivityMapsBinding
import com.mapbox.android.core.location.LocationEngine
import com.mapbox.android.core.location.LocationEngineProvider
import com.mapbox.android.core.location.LocationEngineRequest
import com.mapbox.maps.CameraOptions
import com.mapbox.maps.MapView
import com.mapbox.maps.Style
import com.mapbox.maps.plugin.gestures.gestures
import com.mapbox.maps.plugin.locationcomponent.location
import java.lang.ref.WeakReference
class MapsActivity : AppCompatActivity() {
private lateinit var mapView: MapView
private lateinit var locationEngine: LocationEngine
private val callback = LocationListeningCallback(this)
private lateinit var locationPermissionHelper: LocationPermissionHelper
private lateinit var locationInitHelper: LocationInitHelper
private lateinit var binding: ActivityMapsBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMapsBinding.inflate(layoutInflater)
mapView = MapView(binding.root.context)
setContentView(mapView)
locationInitHelper = LocationInitHelper(WeakReference(this))
locationInitHelper.setMapView(mapView)
mapView.getMapboxMap().loadStyleUri(Style.MAPBOX_STREETS)
locationEngine = LocationEngineProvider.getBestLocationEngine(this)
locationPermissionHelper = LocationPermissionHelper(WeakReference(this))
onMapReady()
}
private fun onMapReady(){
val DEFAULT_INTERVAL_IN_MILLISECONDS = 1000L
val DEFAULT_MAX_WAIT_TIME = DEFAULT_INTERVAL_IN_MILLISECONDS * 5
locationEngine = LocationEngineProvider.getBestLocationEngine(this)
var request = LocationEngineRequest.Builder(DEFAULT_INTERVAL_IN_MILLISECONDS)
.setPriority(LocationEngineRequest.PRIORITY_NO_POWER)
.setMaxWaitTime(DEFAULT_MAX_WAIT_TIME)
.build()
if (ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_FINE_LOCATION
) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(
this,
Manifest.permission.ACCESS_COARSE_LOCATION
) != PackageManager.PERMISSION_GRANTED
) {
locationPermissionHelper.checkPermissions { onMapReady() }
}
locationEngine.requestLocationUpdates(request, callback, mainLooper)
locationEngine.getLastLocation(callback)
mapView.getMapboxMap().setCamera(
CameraOptions.Builder()
.zoom(12.0)
.build()
)
locationInitHelper.initLocationComponent()
locationInitHelper.setupGesturesListener()
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
}
override fun onDestroy() {
super.onDestroy()
mapView.location
.removeOnIndicatorBearingChangedListener(locationInitHelper.onIndicatorBearingChangedListener)
mapView.location
.removeOnIndicatorPositionChangedListener(locationInitHelper.onIndicatorPositionChangedListener)
mapView.gestures.removeOnMoveListener(locationInitHelper.onMoveListener)
}
override fun onStop() {
super.onStop()
locationEngine.removeLocationUpdates(callback)
}
}
Try this
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
xmlns:mapbox="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.mapbox.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="40.7128"
mapbox:mapbox_cameraTargetLng="-74.0060"
mapbox:mapbox_cameraZoom="9.0">
</com.mapbox.maps.MapView>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:backgroundTint="#color/purple_200"
android:layout_margin="16dp"
android:src="#drawable/ic_app_icon"
android:tint="#color/white"
tools:ignore="ImageContrastCheck" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
Try declaring the floating action button outside the mapview like this:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout xmlns:mapbox="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:android="http://schemas.android.com/apk/res/android">
<com.mapbox.maps.MapView
android:id="#+id/mapView"
android:layout_width="match_parent"
android:layout_height="match_parent"
mapbox:mapbox_cameraTargetLat="40.7128"
mapbox:mapbox_cameraTargetLng="-74.0060"
mapbox:mapbox_cameraZoom="9.0"/>
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="#+id/fab"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="end|bottom"
android:backgroundTint="#color/purple_200"
android:layout_margin="16dp"
android:contentDescription="#string/fab_description"
android:src="#drawable/ic_plus_icon"
tools:ignore="ImageContrastCheck" />
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I was able to solve this through MapsActivity.kt. As I suspected the setContentView() was getting the wrong view I replaced that part and assigned view manually to mapView. The script looks like this:
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_maps)
mapView = findViewById(R.id.mapView)
locationInitHelper = LocationInitHelper(WeakReference(this))
locationInitHelper.setMapView(mapView)
mapView.getMapboxMap().loadStyleUri(Style.MAPBOX_STREETS)
locationEngine = LocationEngineProvider.getBestLocationEngine(this)
locationPermissionHelper = LocationPermissionHelper(WeakReference(this))
onMapReady()
}
Thanks for all the answers though!

How is defined MediaRecorder( )?

i make program for record audio for android but i find MediaRecorder() Deprecated
kotlin code
package noteapp.notesnotesnotescairo.mynoteapp
import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.content.Context
import android.content.pm.PackageManager
import android.icu.text.SimpleDateFormat
import android.media.MediaRecorder
import android.os.Build
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.os.Looper
import android.os.Looper.prepare
import androidx.annotation.RequiresApi
import androidx.core.app.ActivityCompat
import kotlinx.android.synthetic.main.activity_main.*
import kotlinx.coroutines.NonCancellable.start
import java.io.IOException
import java.util.*
const val REQUEST_CODE=200
private var permission = arrayOf(Manifest.permission.RECORD_AUDIO)
private var permissionGranted=false
private lateinit var recorder : MediaRecorder
private var dirPath=""
private var filename=""
private var isRecording=false
private var isPaused=false
class MainActivity : AppCompatActivity(){
#RequiresApi(Build.VERSION_CODES.S)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
permissionGranted=ActivityCompat.checkSelfPermission(this, permission[0])==PackageManager.PERMISSION_GRANTED
if(!permissionGranted)
ActivityCompat.requestPermissions(this, permission, REQUEST_CODE)
btnRecord.setOnClickListener{
when{
isPaused->resumeRecorder()
isRecording->pauseRecorder()
else->startRecording()
}
}
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
if(requestCode== REQUEST_CODE)
permissionGranted=grantResults[0]==PackageManager.PERMISSION_GRANTED
}
private fun pauseRecorder(){
recorder.pause()
isPaused=true
btnRecord.setImageResource(R.drawable.ic_record)
}
private fun resumeRecorder(){
recorder.resume()
isPaused=false
btnRecord.setImageResource(R.drawable.ic_pause)
}
#RequiresApi(Build.VERSION_CODES.S)
private fun startRecording(){
if(!permissionGranted){
ActivityCompat.requestPermissions(this, permission, REQUEST_CODE)
return
}
recorder = MediaRecorder( this)
dirPath="${externalCacheDir?.absolutePath}/"
var simpleDateFormat= SimpleDateFormat("yyyy.mm.dd.hh.mm.ss")
var date :String=simpleDateFormat.format(Date())
filename="audio_record_$date"
recorder.apply {
setAudioSource(MediaRecorder.AudioSource.MIC)
setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
setOutputFile("$dirPath$filename.mp3")
try{
prepare()
}catch (e:IOException){}
start()
}
btnRecord.setImageResource(R.drawable.ic_pause)
isRecording=true
isPaused=false
}
}
xml code
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<TextView
android:id="#+id/tvTimer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="00:00:00"
android:textSize="56sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:layout_marginBottom="80dp"
app:layout_constraintBottom_toBottomOf="parent"
>
<ImageButton
android:id="#+id/btnDelete"
android:layout_width="#dimen/btn_size"
android:src="#drawable/ic_delete_disable"
android:layout_height="#dimen/btn_size"
android:background="#drawable/ic_ripple"/>
<ImageButton
android:id="#+id/btnRecord"
android:layout_width="66dp"
android:layout_marginStart="30dp"
android:layout_marginEnd="30dp"
android:layout_height="66dp"
android:background="#drawable/ic_record"/>
<ImageButton
android:id="#+id/btnList"
android:layout_width="#dimen/btn_size"
android:src="#drawable/ic_list"
android:layout_height="#dimen/btn_size"
android:background="#drawable/ic_ripple"/>
<ImageButton
android:id="#+id/btnDone"
android:layout_width="#dimen/btn_size"
android:src="#drawable/ic_done"
android:visibility="gone"
android:layout_height="#dimen/btn_size"
android:background="#drawable/ic_ripple"/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
what is new defind for MediaRecorder() not Deprecated ?
give me error
java.lang.NoSuchMethodError: No direct method (Landroid/content/Context;)V in class Landroid/media/MediaRecorder; or its super classes (declaration of 'android.media.MediaRecorder' appears in /system/framework/framework.jar!classes2.dex)
Use an if/else to set the property using the supported constructor:
recorder = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) MediaRecorder(this) else MediaRecorder()
Down the road it is possible Jetpack will add a helper function that would do this for you, something like MediaRecorderCompat.newInstance(this). However, it has been so long I think we can assume they will probably not be adding it.
I used the following script in an app published on the Playstore
fun prepare_audio_and_directories(v : View) {
var tempDir : File
// current_filename = (v.findViewById(R.id.audio_filename_xml) as TextView).text.toString()
current_dir = main?.dir!!
tempDir = current_dir
main?.filenameCompletePath = tempDir?.toPath().toString() + "/" +current_filename + "."+ main?.ext
main?.filename_text = current_filename
Log.d("$TAG:prepare_audio_and_directories:main?.filenameCompletePath=", main?.filenameCompletePath!!
)
Log.d("$TAG:prepare_audio_and_directories:main?.filename_text=", main?.filename_text!!)
Log.d("NoiseSuppressor.isAvailable()=", NoiseSuppressor.isAvailable().toString() )
mediaRecorder = MediaRecorder()
mediaRecorder?.setAudioSource(MediaRecorder.AudioSource.MIC)
mediaRecorder?.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4)
mediaRecorder?.setAudioEncoder(MediaRecorder.AudioEncoder.AAC)
mediaRecorder?.setAudioEncodingBitRate(128000)
mediaRecorder?.setAudioSamplingRate(96000);
mediaRecorder?.setOutputFile(main?.filenameCompletePath)
}
The versions I tested it with are API 28,29,30 and 31.

I want change profile using image capture on navigation drawer ? its possible?

Navigation drawer
I wrote this code but problem is crash application.
This id my nav_header file xml code,i am using circleimageview and imagebutton.
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginTop="16dp"
android:layout_marginStart="16dp"
android:layout_marginEnd="16dp"
android:layout_marginLeft="16dp"
android:layout_marginRight="16dp"
android:background="#color/white">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/Profile"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_marginStart="10dp"
android:layout_marginTop="10dp"
android:src="#drawable/ic_baseline_person_24"
app:civ_border_color="#color/black"
app:civ_border_width="2dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<ImageButton
android:id="#+id/change_Profile"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/background_center"
app:layout_constraintBottom_toBottomOf="#+id/Profile"
app:layout_constraintEnd_toEndOf="#+id/Profile"
app:srcCompat="#drawable/ic_baseline_add_circle_24" />
<TextView
android:id="#+id/User_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="72dp"
android:paddingTop="8dp"
android:text="Robin Hud"
android:textColor="#color/black"
android:textSize="20dp"
android:textStyle="bold"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="10dp"
android:layout_marginTop="110dp"
android:text="sufiyan123#gmail.com"
android:textSize="16dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginTop="135dp"
android:background="#color/underline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
----------
This is kotlin file code for navigation drawer
package com.example.pgf.view.home
import android.app.Activity
import android.content.Intent
import android.graphics.Bitmap
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.provider.MediaStore
import android.view.MenuItem
import android.widget.ImageButton
import android.widget.Toast
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.drawerlayout.widget.DrawerLayout
import androidx.fragment.app.Fragment
import com.example.pgf.R
import com.example.pgf.model.PGListModel
import com.example.pgf.view.authentication.Login
import com.example.pgf.view.home.fragments.*
import com.google.android.material.floatingactionbutton.FloatingActionButton
import com.google.android.material.navigation.NavigationView
import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.auth.ktx.auth
import com.google.firebase.ktx.Firebase
import de.hdodenhof.circleimageview.CircleImageView
class MainActivity : AppCompatActivity() {
private lateinit var toggle: ActionBarDrawerToggle
private lateinit var drawerLayout: DrawerLayout
var email:String? = null
var profile: CircleImageView? = null
var reqcode = 345
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
//Profile change
profile = findViewById(R.id.Profile)
var btnChange = findViewById<ImageButton>(R.id.change_Profile)
btnChange.setOnClickListener {
var captureImage = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
startActivityForResult(captureImage,reqcode)
}
//get user Email
val user = FirebaseAuth.getInstance().currentUser
email = user?.email
Toast.makeText(applicationContext,email,Toast.LENGTH_SHORT).show()
drawerLayout = findViewById(R.id.drawer)
val navView: NavigationView = findViewById(R.id.navView)
toggle = ActionBarDrawerToggle(this,drawerLayout,R.string.open,R.string.close)
drawerLayout.addDrawerListener(toggle)
toggle.syncState()
supportActionBar?.setDisplayHomeAsUpEnabled(true)
replaceFragment(HomeFragment(),"Home")
navView.setNavigationItemSelectedListener {
it.isChecked = true
when(it.itemId){
R.id.nav_home -> replaceFragment(HomeFragment(),it.title.toString())
R.id.nav_star -> replaceFragment(StarFragment(),it.title.toString())
R.id.nav_help -> replaceFragment(HelpFragment(),it.title.toString())
R.id.nav_setting -> replaceFragment(SettingFragment(),it.title.toString())
R.id.nav_profile -> replaceFragment(ProfileFragment(),it.title.toString())
R.id.nav_logout -> logout()
R.id.nav_share -> Toast.makeText(applicationContext,"Clicked Share",Toast.LENGTH_SHORT).show()
}
true
}
}
private fun replaceFragment(fragment: Fragment, title: String){
val fragmentStateManagerControl = supportFragmentManager
val fragmentTransaction = fragmentStateManagerControl.beginTransaction()
fragmentTransaction.replace(R.id.framelayout,fragment)
fragmentTransaction.commit()
drawerLayout.closeDrawers()
setTitle(title)
}
fun logout(){
Firebase.auth.signOut()
startActivity(
Intent(this,Login::class.java)
)
this.finish()
}
override fun onOptionsItemSelected(item: MenuItem): Boolean {
if (toggle.onOptionsItemSelected(item)){
return true
}
return super.onOptionsItemSelected(item)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if(resultCode== Activity.RESULT_OK && requestCode==reqcode && data!=null)
{
profile!!.setImageBitmap(data.extras?.get("data") as Bitmap)
}
else
{
Toast.makeText(applicationContext,"Something Went Wrong!!",Toast.LENGTH_LONG).show()
}
}
}
This is my all code,so I want to change profile picture using camera capture on navigation drawer.
so what I do for this?
Logcat
enter image description here

My Recyclerview sometimes display data and sometimes it doesnt

My Recyclerview sometimes needs a refresh to start displaying data, some times it need much time to display the data and sometimes it works like a charm. I even used the same adapter for 2 recycler views one of them displayed data immediately but the other didn't show at all like the the image below:
This problem started to show up when I added another recycler view but in a different fragment that used same adapter. I thought using same adapter was the problem so I created a new one but the problem is still there. Note: I'm using same layout for displaying the recycler view items too. Any Ideas would be really helpful.
Thanks
UPDATE: Codes
Adapter :
import android.graphics.Paint
import android.view.LayoutInflater
import android.view.TextureView
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.DiffUtil
import androidx.recyclerview.widget.ListAdapter
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.example.ecommapp.R
import com.example.ecommapp.main_activity.data.Product
import kotlinx.android.synthetic.main.product_item_layout.view.*
class ProductItemAdapter(val listener: ProductItemAdapter.onItemClickListener) : ListAdapter<Product, ProductItemAdapter.ProductViewHolder>(Comparator()) {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ProductViewHolder {
val inflater = LayoutInflater.from(parent.context).inflate(R.layout.product_item_layout, parent, false)
return ProductViewHolder(inflater)
}
override fun onBindViewHolder(holder: ProductViewHolder, position: Int) {
val currentItem = getItem(position)
if (currentItem != null) {
holder.bind(currentItem)
}
}
inner class ProductViewHolder(view : View): RecyclerView.ViewHolder(view){
init {
view.setOnClickListener{
val position = adapterPosition
val product = getItem(position)
if(position != RecyclerView.NO_POSITION){
listener.onItemClick(product)
}
}
}
private val container = view.container_main
private val imageView = view.img_product_item_not_card
private val productName = view.tv_product_item_label
private val productNewPrice = view.tv_product_item_new_price
private val productOldPrice = view.tv_product_item_old_price
fun bind(product: Product) {
productName.text = product.title
productNewPrice.text = product.price
/*var temp = (product.price as Double ) * 1.5
var oldPrice = temp as String
productOldPrice.text = oldPrice
productOldPrice.paintFlags = productOldPrice.paintFlags or Paint.STRIKE_THRU_TEXT_FLAG*/
//Context of the view
Glide.with(imageView.context) // Context
.load(product.image) // Data
.into(imageView) // View
}
}
interface onItemClickListener{
fun onItemClick(product : Product)
}
class Comparator : DiffUtil.ItemCallback<Product>() {
override fun areItemsTheSame(oldItem: Product, newItem: Product) =
oldItem.id == newItem.id
override fun areContentsTheSame(oldItem: Product, newItem: Product) =
oldItem == newItem
}
}
View Model:
import android.content.ContentValues.TAG
import android.util.Log
import androidx.lifecycle.*
import com.example.ecommapp.main_activity.data.Product
import com.example.ecommapp.main_activity.retrofit.ProductsApi
import dagger.hilt.android.lifecycle.HiltViewModel
import dagger.hilt.android.scopes.ViewModelScoped
import kotlinx.coroutines.launch
import retrofit2.Call
import retrofit2.Callback
import retrofit2.Response
import javax.inject.Inject
#HiltViewModel
class HomeViewModel #Inject constructor(
private val savedStateHandle: SavedStateHandle,
val api : ProductsApi
) : ViewModel() {
var new_collection_list : MutableLiveData<List<Product>>
var best_sellling_list : MutableLiveData<List<Product>>
init {
new_collection_list = MutableLiveData()
best_sellling_list = MutableLiveData()
get_best_selling_data()
get_new_collection_data()
}
fun get_new_collection_data(){
var call = api.get_products_desc()
call.enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
if (response.body() != null){
new_collection_list.postValue(response.body())
Log.d(TAG, "onResponse: Success Response")
}
else{
new_collection_list.postValue(null)
Log.d(TAG, "onResponse: Null Response")
}
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
Log.d(TAG, "onFailure: Failure Response")
}
})
}
fun get_best_selling_data() {
var call = api.get_products_asc()
call.enqueue(object : Callback<List<Product>> {
override fun onResponse(call: Call<List<Product>>, response: Response<List<Product>>) {
if (response.body() != null){
best_sellling_list.postValue(response.body())
Log.d(TAG, "onResponse: Success Response")
}
else{
best_sellling_list.postValue(null)
Log.d(TAG, "onResponse: Null Response")
}
}
override fun onFailure(call: Call<List<Product>>, t: Throwable) {
Log.d(TAG, "onFailure: Failure Response")
}
})
}
fun on_swipe_refresh(){
get_new_collection_data()
get_best_selling_data()
}
}
Fragment :
package com.example.ecommapp.main_activity.fragments.home_fragment
import android.content.Context
import android.net.ConnectivityManager
import android.net.NetworkCapabilities
import android.os.Build
import android.os.Bundle
import android.os.Handler
import android.view.View
import android.widget.Toast
import androidx.fragment.app.Fragment
import androidx.fragment.app.viewModels
import androidx.lifecycle.LiveData
import androidx.lifecycle.Observer
import androidx.navigation.fragment.findNavController
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout
import com.example.ecommapp.R
import com.example.ecommapp.main_activity.data.Product
import com.example.ecommapp.main_activity.shared_files.recycler_view_adapters.ProductItemAdapter
import dagger.hilt.android.AndroidEntryPoint
import kotlinx.android.synthetic.main.home_fragment_layout.*
#AndroidEntryPoint
class HomeFragment: Fragment(R.layout.home_fragment_layout), ProductItemAdapter.onItemClickListener {
lateinit var new_collection_list : LiveData<List<Product>>
lateinit var best_selling_list : LiveData<List<Product>>
val new_collections_adapter = ProductItemAdapter(this)
val best_selling_adapter = ProductItemAdapter(this)
val viewModel : HomeViewModel by viewModels()
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
// New Collection Recycler View Setup
rv_new_collections.layoutManager = LinearLayoutManager(
activity?.applicationContext,
LinearLayoutManager.HORIZONTAL,
false
)
rv_new_collections.adapter = new_collections_adapter
// Best Selling Recycler View Setup
rv_best_selling.layoutManager = LinearLayoutManager(
activity?.applicationContext,
LinearLayoutManager.HORIZONTAL,
false
)
rv_best_selling.adapter = best_selling_adapter
//
set_data()
Handler().postDelayed({
if ( isConnected(activity?.applicationContext) ){
layout_new_collection_shimmer.visibility = View.INVISIBLE
rv_new_collections.visibility = View.VISIBLE
layout_best_selling_shimmer.visibility = View.INVISIBLE
rv_best_selling.visibility = View.VISIBLE
set_data()
}
else{
Toast.makeText(activity?.applicationContext, "No Internet Connection, Swipe to reload.", Toast.LENGTH_LONG )
.show()
}
}, 2000)
container_swipe.setOnRefreshListener(object : SwipeRefreshLayout.OnRefreshListener {
override fun onRefresh() {
if ( isConnected(activity?.applicationContext) ){
if( layout_new_collection_shimmer.visibility == View.INVISIBLE){
layout_new_collection_shimmer.visibility = View.INVISIBLE
rv_new_collections.visibility = View.VISIBLE
layout_best_selling_shimmer.visibility = View.INVISIBLE
rv_best_selling.visibility = View.VISIBLE
}
viewModel.on_swipe_refresh()
set_data()
}
else{
Toast.makeText(activity?.applicationContext, "No Internet Connection, Swipe to reload.", Toast.LENGTH_LONG )
.show()
}
// Must be added
container_swipe.isRefreshing = false
}
})
}
fun set_data(){
new_collection_list = viewModel.new_collection_list
best_selling_list = viewModel.best_sellling_list
new_collection_list.observe(viewLifecycleOwner, Observer {
new_collections_adapter.submitList(it)
new_collections_adapter.notifyDataSetChanged()
})
best_selling_list.observe(viewLifecycleOwner, Observer {
best_selling_adapter.submitList(it)
best_selling_adapter.notifyDataSetChanged()
})
}
fun isConnected(ctx: Context?): Boolean {
val hasInternet: Boolean
val connectivityManager =
ctx?.getSystemService(Context.CONNECTIVITY_SERVICE) as ConnectivityManager
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
val networkCapabilities = connectivityManager.activeNetwork ?: return false
val actNw =
connectivityManager.getNetworkCapabilities(networkCapabilities) ?: return false
hasInternet = when {
actNw.hasTransport(NetworkCapabilities.TRANSPORT_WIFI) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_CELLULAR) -> true
actNw.hasTransport(NetworkCapabilities.TRANSPORT_ETHERNET) -> true
else -> false
}
} else {
hasInternet = try {
if (connectivityManager.activeNetworkInfo == null) {
false
} else {
connectivityManager.activeNetworkInfo?.isConnected!!
}
} catch (e: Exception) {
false
}
}
return hasInternet}
override fun onItemClick(product : Product) {
val action = HomeFragmentDirections.actionHomeFragmentToProductFragment(product, product.title, R.id.homeFragment)
findNavController().navigate(action)
}
}
Layout:
<?xml version="1.0" encoding="utf-8"?>
<androidx.swiperefreshlayout.widget.SwipeRefreshLayout
android:id="#+id/container_swipe"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
tools:context=".main_activity.fragments.home_fragment.HomeFragment"
>
<ScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.appcompat.widget.SearchView
android:id="#+id/search_view"
android:layout_width="0dp"
android:layout_height="50dp"
app:layout_constraintWidth_percent="0.9"
android:elevation="2dp"
android:outlineProvider="bounds"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:layout_marginTop="20dp"/>
<androidx.cardview.widget.CardView
android:id="#+id/img_advertisment"
android:layout_width="0dp"
android:layout_height="180dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/search_view"
app:layout_constraintWidth_percent="0.9"
android:background="#00000000"
app:cardElevation="0dp"
app:cardCornerRadius="10dp"
>
<ImageView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:src="#drawable/advertisment"
/>
</androidx.cardview.widget.CardView>
<RelativeLayout
android:id="#+id/container_new_collection"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/img_advertisment"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.9"
android:layout_marginTop="20dp"
>
<TextView
android:id="#+id/tv_new_collection"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Collections"
android:textColor="#color/tomato"
android:textSize="25dp"
android:fontFamily="sans-serif-black"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show All"
android:textSize="20dp"
android:textColor="#c6c4ce"
android:fontFamily="sans-serif-black"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="5dp"/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/layout_new_collection_shimmer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:shimmer_repeat_mode="restart"
app:shimmer_shape="linear"
android:layout_below="#id/tv_new_collection"
android:layout_marginTop="10dp">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
</LinearLayout>
</HorizontalScrollView>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:layout_marginTop="10dp"
android:id="#+id/rv_new_collections"
android:layout_width="wrap_content"
android:layout_height="350dp"
android:layout_below="#id/tv_new_collection"
tools:listitem="#layout/product_item_layout"
android:visibility="invisible"
/>
</RelativeLayout>
<RelativeLayout
android:id="#+id/container_best_selling"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="#id/container_new_collection"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintWidth_percent="0.9"
android:layout_marginTop="20dp"
>
<TextView
android:id="#+id/tv_best_selling"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Best Selling"
android:textColor="#color/tomato"
android:textSize="25dp"
android:fontFamily="sans-serif-black"
android:layout_alignParentTop="true"
android:layout_alignParentLeft="true"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show All"
android:textSize="20dp"
android:textColor="#c6c4ce"
android:fontFamily="sans-serif-black"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_marginTop="5dp"
/>
<com.facebook.shimmer.ShimmerFrameLayout
android:id="#+id/layout_best_selling_shimmer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:shimmer_repeat_mode="restart"
app:shimmer_shape="linear"
android:layout_marginTop="10dp"
android:layout_below="#id/tv_best_selling">
<HorizontalScrollView
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
<include layout="#layout/product_shimmer_layout"></include>
</LinearLayout>
</HorizontalScrollView>
</com.facebook.shimmer.ShimmerFrameLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rv_best_selling"
android:layout_width="wrap_content"
android:layout_height="350dp"
android:layout_below="#id/tv_best_selling"
tools:listitem="#layout/product_item_layout"
android:layout_marginTop="10dp"
android:visibility="invisible"
/>
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</ScrollView>
</androidx.swiperefreshlayout.widget.SwipeRefreshLayout>
I Figured out what is the problem. The API takes much time to send the data. So, the recycler view renders the view with null values.

RecyclerView doesn't scroll smoothly initially

I'm using Tmdb API and displaying it in a RecyclerView. The RecyclerView is not scrolling smoothly initially but then is working fine. I've tried to change Recyclerview height to 0dp or match_parent but it's still the same. I've tried also android:nestedScrollingEnabled="true". Please help me to fix this problem in the RecyclerView. Thank you in advance.
fragment_add.xml
<?xml version="1.0" encoding="utf-8"?>
<layout 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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".view.AddFragment">
<androidx.appcompat.widget.AppCompatAutoCompleteTextView
android:id="#+id/fragment_add_movieSeriesACT"
android:layout_width="match_parent"
android:layout_height="50dp"
android:layout_marginStart="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
android:background="#drawable/edit_text_background"
android:hint="#string/movie_or_series"
android:imeOptions="actionDone"
android:inputType="textEmailAddress"
android:paddingStart="8dp"
android:paddingEnd="8dp"
android:textColor="#color/colorPrimary"
android:textColorHint="#color/colorEight"
android:textCursorDrawable="#null"
android:textSize="15sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/fragment_add_mainRV"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:scrollbars="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/fragment_add_movieSeriesACT" />
<ProgressBar
android:id="#+id/fragment_add_mainPB"
style="?android:attr/progressBarStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:indeterminate="true"
android:indeterminateTint="#color/colorOne"
android:indeterminateTintMode="src_atop"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
AddFragment.kt
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.Toast
import androidx.lifecycle.Observer
import androidx.lifecycle.ViewModelProviders
import androidx.recyclerview.widget.LinearLayoutManager
import com.martiandeveloper.muuvi.R
import com.martiandeveloper.muuvi.adapter.RecyclerViewMovieAdapter
import com.martiandeveloper.muuvi.viewmodel.AddViewModel
import kotlinx.android.synthetic.main.fragment_add.*
class AddFragment : Fragment() {
private lateinit var viewModel: AddViewModel
private val adapter = RecyclerViewMovieAdapter(arrayListOf())
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
return inflater.inflate(R.layout.fragment_add, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
initUI()
}
private fun initUI() {
viewModel = ViewModelProviders.of(this).get(AddViewModel::class.java)
setRecyclerView()
observe()
viewModel.refreshData()
}
private fun setRecyclerView() {
fragment_add_mainRV.layoutManager = LinearLayoutManager(context)
fragment_add_mainRV.adapter = adapter
}
private fun observe() {
viewModel.movieList.observe(viewLifecycleOwner, Observer { movieList ->
movieList?.let {
adapter.updateMovieList(it)
}
})
viewModel.isError.observe(viewLifecycleOwner, Observer { isError ->
isError?.let {
setProgress(1F, true, View.GONE)
if (it) {
setToast(resources.getString(R.string.something_went_wrong_please_try_again_later))
}
}
})
viewModel.isLoading.observe(viewLifecycleOwner, Observer { isLoading ->
isLoading?.let {
if (it) {
setProgress(.5F, false, View.VISIBLE)
} else {
setProgress(1F, true, View.GONE)
}
}
})
}
private fun setProgress(alpha: Float, enable: Boolean, visible: Int) {
fragment_add_movieSeriesACT.alpha = alpha
fragment_add_mainRV.alpha = alpha
fragment_add_movieSeriesACT.isEnabled = enable
fragment_add_mainPB.visibility = visible
}
private fun setToast(text: String) {
Toast.makeText(context, text, Toast.LENGTH_SHORT).show()
}
}
AddViewModel.kt
import androidx.lifecycle.MutableLiveData
import androidx.lifecycle.ViewModel
import com.martiandeveloper.muuvi.model.MovieResult
import com.martiandeveloper.muuvi.model.Movie
import com.martiandeveloper.muuvi.service.MovieService
import io.reactivex.android.schedulers.AndroidSchedulers
import io.reactivex.disposables.CompositeDisposable
import io.reactivex.observers.DisposableSingleObserver
import io.reactivex.schedulers.Schedulers
class AddViewModel : ViewModel() {
private val movieService = MovieService()
private val disposable = CompositeDisposable()
val movieList = MutableLiveData<List<Movie>>()
val isError = MutableLiveData<Boolean>()
val isLoading = MutableLiveData<Boolean>()
fun refreshData() {
isLoading.value = true
disposable.add(
movieService.getData().subscribeOn(Schedulers.newThread())
.observeOn(AndroidSchedulers.mainThread())
.subscribeWith(object : DisposableSingleObserver<MovieResult>() {
override fun onSuccess(t: MovieResult) {
movieList.value = t.results
isError.value = false
isLoading.value = false
}
override fun onError(e: Throwable) {
isError.value = true
isLoading.value = false
}
})
)
}
}
RecyclerViewMovieAdapter.kt
import android.content.Context
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.bumptech.glide.Glide
import com.martiandeveloper.muuvi.R
import com.martiandeveloper.muuvi.model.Movie
import kotlinx.android.synthetic.main.recyclerview_movie_item.view.*
class RecyclerViewMovieAdapter(private val movieList: ArrayList<Movie>) :
RecyclerView.Adapter<RecyclerViewMovieAdapter.RecyclerViewMovieViewHolder>() {
lateinit var context: Context
class RecyclerViewMovieViewHolder(var view: View) : RecyclerView.ViewHolder(view)
override fun onCreateViewHolder(
parent: ViewGroup,
viewType: Int
): RecyclerViewMovieViewHolder {
context = parent.context
val view = LayoutInflater.from(context)
.inflate(R.layout.recyclerview_movie_item, parent, false)
return RecyclerViewMovieViewHolder(view)
}
override fun getItemCount(): Int {
return movieList.size
}
override fun onBindViewHolder(holder: RecyclerViewMovieViewHolder, position: Int) {
holder.view.recyclerview_movie_item_movieTitleMTV.text =
movieList[position].movieTitle
holder.view.recyclerview_movie_item_movieVoteAverageMTV.text =
movieList[position].movieVoteAverage.toString()
Glide.with(context)
.load("https://image.tmdb.org/t/p/w300${movieList[position].moviePosterPath}")
.into(holder.view.recyclerview_movie_item_moviePosterIV)
}
fun updateMovieList(newMovieList: List<Movie>) {
movieList.clear()
movieList.addAll(newMovieList)
notifyDataSetChanged()
}
}
recyclerview_movie_item.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingStart="16dp"
android:paddingTop="8dp"
android:paddingEnd="8dp"
android:paddingBottom="8dp">
<androidx.cardview.widget.CardView
android:layout_width="80dp"
android:layout_height="80dp"
app:cardBackgroundColor="#android:color/transparent"
app:cardCornerRadius="10dp"
app:cardElevation="0dp">
<ImageView
android:id="#+id/recyclerview_movie_item_moviePosterIV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:contentDescription="#string/app_name"
android:scaleType="centerCrop"
app:srcCompat="#drawable/default_user_image" />
</androidx.cardview.widget.CardView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:orientation="vertical">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/recyclerview_movie_item_movieTitleMTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/colorPrimary"
android:textSize="18sp"
android:textStyle="bold" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/recyclerview_movie_item_movieVoteAverageMTV"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textColor="#color/colorPrimaryDark" />
</LinearLayout>
</LinearLayout>
I believe this is due to size of the image , I had similar issue try to fit the image you obtain using glide into imageview, I have added centerCrop():
Glide.with(context).load("https://image.tmdb.org/t/p/w300${movieList[position].moviePosterPath}") .centerCrop().into(holder.view.recyclerview_movie_item_moviePosterIV);
If this does not work try to change imageview scaletype or centerCrop() to fitCenter()

Categories

Resources