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?
Related
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)
}
}
I have one relative layout and one ImageView. I want to set visibility based on Image loading like if image loads successfully then imageview is visible and if some error occurs relative layout is visible. How can I manage this scenario in data binding using BindingAdapter ?
Your question is not clear so I don't know if it will help you.
These are steps to implement
1: Create parameters in BindingAdapter.kt
#BindingAdapter("showLoading")
fun View.showLoading(loading: Boolean) {
if (loading) {
visible()
} else {
gone()
}
}
#BindingAdapter("showError")
fun View.showError(error: Boolean) {
if (error) {
visible()
} else {
gone()
}
}
fun View.gone() {
this.visibility = View.GONE
}
fun View.visible() {
this.visibility = View.VISIBLE
}
2: Use parameters [app:showLoading="#{viewModel.showLoading}"] and [app:showError="#{viewModel.showError}"] created in file 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">
<data>
<variable
name="viewModel"
type="com.xxx.xxx.MainViewModel" />
</data>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#EAEAE2"
android:orientation="vertical">
<Button
android:id="#+id/btnAdd"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ShowLoading" />
<ProgressBar
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:showLoading="#{viewModel.showLoading}" />
<RelativeLayout
android:id="#+id/viewError"
android:layout_width="100dp"
android:layout_height="100dp"
android:background="#color/colorPrimary"
app:showError="#{viewModel.showError}" />
</LinearLayout>
</layout>
3: Create showError and showLoading variables in Viewmodel.
And assign the viewModel variable to the binding.
class MainViewModel: ViewModel() {
val showError: MutableLiveData<Boolean> = MutableLiveData()
val showLoading: MutableLiveData<Boolean> = MutableLiveData()
init {
showError.postValue(false)
showLoading.postValue(true)
}
}
class MainActivity : AppCompatActivity() {
private val viewModel = MainViewModel()
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.lifecycleOwner = this
binding.viewModel = viewModel
initViews()
}
private fun initViews() {
binding.btnAdd.setOnClickListener {
viewModel.showError.postValue(true)
viewModel.showLoading.postValue(false)
}
}
}
I am trying to display Fragment but I do not know why I can't do that. Here is my code:
The main_activity.xml:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
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"
tools:context=".view.MainActivity">
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/fragment_container" />
</androidx.constraintlayout.widget.ConstraintLayout>
Followed by MainActivity.kt:
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
super.onCreate(savedInstanceState, persistentState)
setContentView(R.layout.main_activity)
supportFragmentManager.beginTransaction().apply {
replace(R.id.fragment_container, CurrencyListFragment())
addToBackStack(null)
commit()
}
}
}
The layout currency_list_fragment.xml:
<?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=".view.CurrencyListFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/rvItem"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"/>
<ProgressBar
android:id="#+id/progress_bar"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="visible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
Another class CurrencyListFragment.kt:
class CurrencyListFragment : Fragment(), MainContract.View {
private val restModel: RestModel = RestModel()
lateinit var mainPresenter: MainPresenter
var isLoading: Boolean = false
var apiResponseList: MutableList<ApiResponse> = arrayListOf()
lateinit var itemAdapter: ItemAdapter
var handler: Handler = Handler()
lateinit var _layoutManager: LinearLayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
Log.e("a","a")
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
Log.e("a","a")
return inflater.inflate(R.layout.currency_list_fragment,container,false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
Log.e("a1","a1")
_layoutManager = LinearLayoutManager(activity)
mainPresenter = activity?.let { MainPresenter(this, it.getPreferences(Context.MODE_PRIVATE)) }!!
val currentDate = mainPresenter.convertDate()
mainPresenter.makeACall("2021-07-22")
addScrollerListener()
}
private fun addScrollerListener() {
rvItem.addOnScrollListener(object : RecyclerView.OnScrollListener() {
override fun onScrollStateChanged(_rvItem: RecyclerView, newState: Int) {
super.onScrollStateChanged(_rvItem, newState)
if (!isLoading) {
if (!_rvItem.canScrollVertically(1)) {
loadMore()
isLoading = true
}
}
}
})
}
private fun loadMore() {
//notify adapter using Handler.post() or RecyclerView.post()
handler.post {
apiResponseList.add(ApiResponse("", "", listOf(Currency2("", 0f)), true))
itemAdapter.notifyItemInserted(apiResponseList.size - 1)
}
handler.postDelayed({
apiResponseList.removeAt(apiResponseList.size - 1)
val listSize = apiResponseList.size
itemAdapter.notifyItemRemoved(listSize)
val nextLimit = listSize + 1
for (i in listSize until nextLimit) {
apiResponseList.add(
ApiResponse("", "2020-06-11", listOf(Currency2("a", 2f)), false)
)
}
itemAdapter.notifyDataSetChanged()
isLoading = false
}, 2000)
}
override fun onDestroy() {
super.onDestroy()
restModel.cancelJob()
}
}
Neither of onCreate(), onCreateView() nor onViewCreated() are not called (I suppose that because Logs texts are not shown in Logcat. I guess I added everything you need to solve my problem but if I am wrong and you need something more just ask. Why is that so?
Thank you very much for help!
It turned out I overrided wrong onCreate method on my class extending AppCompatActivity.
I am implementing on Click listener in Kotlin and it is not working. When i click on button nothing happens. Below is the code:
class MainActivity : AppCompatActivity(), View.OnClickListener{
var area: MaterialButton? = null; var length: MaterialButton? = null
var time: MaterialButton? = null;
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
area = findViewById(R.id.button_area)
length = findViewById(R.id.button_length)
time = findViewById(R.id.button_time)
setClickListeners()
}
private fun setClickListeners() {
area?.setOnClickListener(this)
length?.setOnClickListener(this)
time?.setOnClickListener(this)
}
fun toggleDrawer(view: View) {
showToast("Drawer")
}
fun openSettings(view: View) {}
override fun onClick(v: View) {
when (v.id) {
R.id.button_area, R.id.button_length,
R.id.button_time -> showToast("Click")
else ->{
showToast("Drawer")
}
}
}
private fun showToast(str: String){
Toast.makeText(this,str,Toast.LENGTH_LONG).show()
}
}
XML onClick attribute is not working.
<include
layout="#layout/toolbar_content"/>
I have included layout with include property, in main activity(xml). Included view onClick methods are:
fun toggleDrawer(view: View) {
showToast("Drawer")
}
fun openSettings(view: View) {}
They are not working. Infact i am getting error. Could not find a method toggleDrawer(View) in the activity class android.view.ContextThemeWrapper for onClick handler on view class com.google.android.material.button.MaterialButton with id 'drawer_icon'. I have declared these methods in MaterialButton tag. The layout of this button is toolbar_content.
How to resolve all these issues.
If You want to set onClick to specific View in the included layout use this in onCreate:
// Apply click listener to one view in the included layout
val includedLayoutButton: View = findViewById<View>(R.id.includedLayout).findViewById(R.id.butInIncludedLayout)
includedLayoutButton.setOnClickListener {
Log.d("in", "on click")
}
main.xml
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<include
android:id="#+id/includedLayout"
layout="#layout/layout_test" />
</androidx.constraintlayout.widget.ConstraintLayout>
layout_test.xml
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/root"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<Button
android:id="#+id/butInIncludedLayout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button" />
</FrameLayout>
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
}