I'm passing a String url from Fragment A to B, and load to imageView
if (obj?.signature_image?.url != null) {
Glide.with(activity)
.load(obj?.signature_image?.url.toString())
.into(imgSignature)
}
When the imgSinature is clicked, a custom dialog will be pop up, and I want to set the image to the dialog. How can I achieve?
signDialog = Util().dialogSignature(getActivity())
imgSignature.setOnClickListener {
signDialog.show()
if (obj?.signature_image?.url != null) {
signDialog.relativeLayout2.addView(obj?.signature_image?.url)
}
}
Util
fun dialogSignature(context: Context?):Dialog{
var dialog = Dialog(context)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(R.layout.dialog_signature)
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
return dialog
}
dialog_signature
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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:id="#+id/relativeLayout1"
android:layout_width="match_parent"
android:layout_height="230dp"
android:orientation="vertical"
android:background="#android:color/white">
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content"
android:background="#color/colorPrimaryShadow"
android:orientation="horizontal"
android:id="#+id/linearLayout1"
android:gravity="center"
android:layout_marginBottom="2dp" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintBottom_toTopOf="#+id/relativeLayout2" app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent">
<TextView
android:layout_marginLeft="10dp"
android:layout_weight="0.4"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:text="Place Signature"
android:textSize="17sp"
android:layout_gravity="right"/>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_marginRight="10dp"
android:id="#+id/doneTxt"
android:text="Done"
android:textColor="#color/colorDarkBlue"/>
</LinearLayout>
<RelativeLayout android:layout_width="0dp" android:layout_height="0dp"
android:id="#+id/relativeLayout2"
android:background="#color/colorWhite"
app:layout_constraintTop_toBottomOf="#+id/linearLayout1" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="1.0">
</RelativeLayout>
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_below="#+id/linearLayout1"
android:textColor="#color/colorDarkBlue"
android:text="Clear" app:layout_constraintStart_toStartOf="parent"
android:layout_marginStart="8dp" app:layout_constraintEnd_toEndOf="parent"
android:layout_marginEnd="8dp" app:layout_constraintHorizontal_bias="1.0"
android:layout_marginBottom="16dp" app:layout_constraintBottom_toBottomOf="parent"
android:id="#+id/clearTxt"/>
</android.support.constraint.ConstraintLayout>
Error in this line signDialog.relativeLayout2.addView(obj?.signature_image?.url)
Type mismatch. Required: View! Found: String?
Really annoying....
It looks like your post is mostly code; please add some more details.
You are trying to add a url string to a view which is wrong.
Add an ImageView inside your relativeLayout2 and use Glide to load your image url
<RelativeLayout
android:layout_width="0dp"
android:layout_height="0dp"
android:id="#+id/relativeLayout2"
android:background="#color/colorWhite"
app:layout_constraintTop_toBottomOf="#+id/linearLayout1"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintHorizontal_bias="1.0">
<ImageView
android:id="#+id/your_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</RelativeLayout>
and in your onClick
imgSignature.setOnClickListener {
...
Glide.with(activity)
.load(obj?.signature_image?.url.toString())
.into(signDialog.your_image)
}
You have to add an ImageView in dialog_signautre.xml and then pass the signature_image?.url in a second parameter and set it like this
fun dialogSignature(context: Context?,url:String?):Dialog{
var dialog = Dialog(context)
dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
dialog.setContentView(R.layout.dialog_signature)
val imgSignature = dialog.findViewById<ImageView>(your_imageview_id)//added this line
Glide.with(activity)
.load(obj?.signature_image?.url.toString())
.into(imgSignature) //added this line
dialog.getWindow().setLayout(ViewGroup.LayoutParams.MATCH_PARENT,ViewGroup.LayoutParams.WRAP_CONTENT);
return dialog
}
Related
I'm creating a View Stub for my login screen, however I have a question. When I try to set an setOnClickListener on my login button in my viewstub_login.kt file, the button action won't go through. Do I need to change my extension on my Kotlin file, or do I need to put my setOnClickListener in the onStart() function? Thank you!
viewstub_login.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"
android:background="#BF090909">
<androidx.cardview.widget.CardView
android:id="#+id/loginCardView"
android:layout_width="0dp"
android:layout_height="300dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
app:cardBackgroundColor="#color/main_purple"
app:cardCornerRadius="8dp"
app:cardElevation="5dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ImageView
android:id="#+id/logoLoginImageView"
android:layout_width="90dp"
android:layout_height="35dp"
android:layout_marginTop="12dp"
android:contentDescription="#string/login_logo_image"
android:scaleType="fitXY"
android:src="#drawable/skedaddle_services_"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/emailTextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:textColorHint="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/logoLoginImageView">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/emailInputTextView"
android:layout_width="match_parent"
android:layout_height="48dp"
android:background="#drawable/textview_underlinr"
android:drawableStart="#drawable/outline_mail_white_24"
android:drawablePadding="5dp"
android:hint="#string/e_mail"
android:textColor="#color/white"
android:textColorHint="#color/white" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.textfield.TextInputLayout
android:id="#+id/passwordTextInputLayout"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginTop="12dp"
android:layout_marginEnd="24dp"
android:hint="#string/password"
android:textColorHint="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/emailTextInputLayout"
app:passwordToggleEnabled="true"
app:passwordToggleTint="#color/white">
<com.google.android.material.textfield.TextInputEditText
android:id="#+id/passwordTextInputView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/textview_underlinr"
android:drawableStart="#drawable/outline_lock_white_24"
android:drawablePadding="5dp"
android:hint="#string/password"
android:inputType="textPassword"
android:textColor="#color/white"
android:textColorHint="#color/white" />
</com.google.android.material.textfield.TextInputLayout>
<Button
android:id="#+id/forgotPasswordButton"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:background="#android:color/transparent"
android:text="#string/forgot_password"
android:textAlignment="textEnd"
android:textAllCaps="false"
android:textColor="#color/white"
android:textSize="12sp"
android:textStyle="italic"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/passwordTextInputLayout" />
<Button
android:id="#+id/cancelButton"
android:layout_width="120dp"
android:layout_height="48dp"
android:background="#color/black"
android:text="#android:string/cancel"
android:textAllCaps="false"
android:textColor="#color/white"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/secondLoginButton"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/forgotPasswordButton" />
<Button
android:id="#+id/secondLoginButton"
android:layout_width="120dp"
android:layout_height="48dp"
android:layout_marginStart="32dp"
android:background="#color/main_teal"
android:text="#string/log_in"
android:textAllCaps="false"
android:textColor="#FFFFFF"
app:layout_constraintBottom_toBottomOf="#+id/cancelButton"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#+id/cancelButton"
app:layout_constraintTop_toTopOf="#+id/cancelButton"
tools:ignore="TextContrastCheck" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>
viewstub_login.kt
class LoginViewStub : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.viewstub_login)
val emailTextView = findViewById<TextInputEditText>(R.id.emailInputTextView)
val passwordTextView = findViewById<TextInputEditText>(R.id.passwordTextInputView)
val forgetPasswordButton = findViewById<Button>(R.id.forgotPasswordButton)
val loginButton = findViewById<Button>(R.id.secondLoginButton)
val cancelButton = findViewById<Button>(R.id.cancelButton)
val emailText = emailTextView.text
val passwordText = passwordTextView.text
loginButton.setOnClickListener {
if (emailText.isEmpty(emailTextView.text) || passwordText.isEmpty(passwordTextView.text)) {
val dialogBuilder = AlertDialog.Builder(this)
dialogBuilder.setMessage("Please fill out all fields.").setCancelable(false).setPositiveButton("Okay", DialogInterface.OnClickListener {
dialog, id -> finish()
}).setNegativeButton("Cancel", DialogInterface.OnClickListener {
dialog, id -> dialog.cancel()
})
val alert = dialogBuilder.create()
alert.show()
}
}
cancelButton.setOnClickListener {
}
forgetPasswordButton.setOnClickListener {
}
}
}
private fun Boolean.isEmpty(str: CharSequence?): Boolean {
return str == null || str.length == 0
}
click listener is correct, but inside the block, your code is not correct
because emailText and passwordText is not null, as you have defined above, thus the if condition returning false and your code just going over it
How can I make a custom view to take only 33% of the screen and make it show proportionately on every device?
This should be handled either on the xml files below, or in the custom view kotlin class, since it's part of a library and I don't have access to the view that will host my custom class.
buff_view.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="#+id/mainLinearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<include layout="#layout/buff_sender"/>
<include layout="#layout/buff_question"/>
<LinearLayout
android:id="#+id/answersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
buff_sender.xml
<?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="wrap_content"
android:layout_marginBottom="4dp"
android:orientation="horizontal">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/light_bg"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<ImageView
android:id="#+id/sender_image"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_gravity="center_vertical"
android:padding="4dp" />
<TextView
android:id="#+id/sender_name"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="4dp"
tools:text="Praveen"
android:textColor="#color/test_color_dark"
android:textStyle="bold" />
</LinearLayout>
<androidx.appcompat.widget.AppCompatImageButton
android:id="#+id/buff_close"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_alignParentEnd="true"
android:background="#drawable/ic_btn_close" />
</RelativeLayout>
buff_question.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="#drawable/dark_bg"
android:orientation="horizontal">
<TextView
android:id="#+id/question_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical|start"
android:padding="18dp"
android:textColor="#color/test_color_light"
android:textStyle="bold"
tools:text="Where do you think Jorge will put this penalty? I'd go left here! Hehehehehehehehehehe super long text" />
<FrameLayout
android:layout_width="32dp"
android:layout_height="32dp">
<ProgressBar
android:id="#+id/question_time_progress"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:indeterminate="false"
android:indeterminateDuration="1"
android:max="100"
android:progress="0" />
<TextView
android:id="#+id/question_time"
android:layout_width="26dp"
android:layout_height="26dp"
android:layout_gravity="center"
android:gravity="center"
android:textColor="#color/test_color_light"
android:textStyle="bold"
tools:text="14" />
</FrameLayout>
</LinearLayout>
buff_answer.xml (which will be injected in the answersContainer from buff_view.xml dynamically depending on the number of answers available for that question)
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="8dp"
android:background="#drawable/light_bg"
android:orientation="horizontal"
tools:ignore="RtlHardcoded">
<ImageView
android:id="#+id/answer_image"
android:layout_width="27dp"
android:layout_height="27dp"
android:layout_gravity="center_vertical"
android:src="#drawable/ic_generic_answer"
android:padding="4dp" />
<TextView
android:id="#+id/answer_text"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:padding="4dp"
android:textColor="#color/test_color_dark"
tools:text="The keeper's right"
android:textStyle="bold" />
</LinearLayout>
BuffView.kt
class BuffView #JvmOverloads constructor(context: Context, attrs: AttributeSet? = null)
: LinearLayout(context, attrs) {
private val apiErrorHandler = ApiErrorHandler()
private val getBuffUseCase = GetBuffUseCase(apiErrorHandler)
private val intervalsHandler = Handler()
private val buffView: LinearLayout = inflate(context, R.layout.buff_view, this) as LinearLayout
private var errorListener: ErrorListener? = null
private var countDownTimer: CountDownTimer? = null
private var buffIdCount = 1
private var getBuffs = false
fun init() {
getBuffs = true
getBuff()
}
private fun getBuff() {
if (!getBuffs) return
getBuffUseCase.invoke(Params(buffIdCount.toLong()), object : UseCaseResponse<Buff> {
override fun onSuccess(result: Buff) {
displayBuff(result)
}
override fun onError(errorModel: ErrorModel?) {
errorListener?.onError( errorModel?.message?: "An error has occurred")
hideBuff()
}
})
if (buffIdCount < TOTAL_BUFFS ) {
intervalsHandler.postDelayed({
buffIdCount++
getBuff()
stopCountDownTimer()
}, REQUEST_BUFF_INTERVAL_TIME)
}
}
private fun displayBuff(buff: Buff) {
setQuestion(buff.question.title)
setAuthor(buff.author)
setAnswer(buff.answers)
setProgressBar(buff.timeToShow)
setCloseButton()
invalidate()
showBuff()
}
private fun setQuestion(questionText: String) {
question_text.text = questionText
}
private fun setAuthor(author: Buff.Author) {
val firstName = author.firstName
val lastName = author.lastName
sender_name.text = "$firstName $lastName"
Glide.with(buffView)
.load(author.image)
.into(sender_image)
}
private fun setAnswer(answers: List<Buff.Answer>) {
val answersContainer = findViewById<LinearLayout>(R.id.answersContainer)
answersContainer.removeAllViews()
for(answer in answers) {
val answerView: View = LayoutInflater.from(answersContainer.context).inflate(
R.layout.buff_answer,
answersContainer,
false
)
answer.answerImage?.x0?.url?.let {
Glide.with(buffView)
.load(it)
.into(answerView.answer_image)
}
answerView.setOnClickListener {
answerView.background = ContextCompat.getDrawable(context, R.drawable.answer_selected_bg)
answerView.answer_text.setTextColor(ContextCompat.getColor(context, android.R.color.white))
//freeze timer
stopCountDownTimer()
//hideView() after 2 seconds
it.postDelayed(Runnable {
hideBuff()
}, HIDE_BUFF_AFTER_SELECTED_ANSWER_DURATION)
}
answerView.answer_text?.text = answer.title
answersContainer.addView(answerView)
}
}
...
}
You'll have to include your buff_view.xml as a child of a layout where you can set the layout_weight property like this.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:gravity="bottom">
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<include layout="#layout/buff_view">
</LinearLayout>
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="2" />
</LinearLayout>
Also change the width and height constraints for the buff view top LinearLayout like this
<LinearLayout
android:id="#+id/mainLinearLayout"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/buff_sender"/>
<include layout="#layout/buff_question"/>
<LinearLayout
android:id="#+id/answersContainer"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"/>
</LinearLayout>
EDIT: Progress bar not visible problem
I think it is a problem with the TextView question_text
Change it like this
<TextView
android:id="#+id/question_text"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical|start"
android:padding="18dp"
android:textColor="#color/test_color_light"
android:textStyle="bold" />
Also change the main Layout in buff_question.xml and set its layout_width to match_parent like this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/dark_bg"
android:orientation="horizontal">
This is easily done using ConstraintLayout and width/height percentages.
Be sure to set the actual width dimensions to 0dp (where using a percentage value) and to make sure the views are constrained appropriately.
The below produces this output
<?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"
android:layout_width="match_parent"
android:layout_height="match_parent">
<View
android:background="#color/salmon1"
android:id="#+id/view1"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent=".33"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<View
android:background="#color/orange1"
android:id="#+id/view2"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/view1" />
</androidx.constraintlayout.widget.ConstraintLayout>
ScreenRecording
I like the animation of the cardView at the top, but the views below arent animated and just snap in place. How can I animate them in a way that there is no overlapping? This is not a recyclerView, these are individual cardViews.
Code for the CardView at the top:
imageViewMuellExtend = (ImageView) root.findViewById(R.id.imageViewMuellExtend);
imageViewMuellExtend.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
muell_extend = (ConstraintLayout) root.findViewById(R.id.muell_extend);
cardViewMuell = (CardView) root.findViewById(R.id.cardViewMuell);
if(muell_extend.getVisibility() == View.GONE){
TransitionManager.beginDelayedTransition(cardViewMuell, new AutoTransition());
muell_extend.setVisibility(View.VISIBLE);
imageViewMuellExtend.setBackgroundResource(R.drawable.ic_keyboard_arrow_up_black_24dp);
} else {
TransitionManager.beginDelayedTransition(cardViewMuell, new AutoTransition());
muell_extend.setVisibility(View.GONE);
imageViewMuellExtend.setBackgroundResource(R.drawable.ic_keyboard_arrow_down_black_24dp);
}
}
});
XML Layout of the CardView:
<androidx.cardview.widget.CardView
android:id="#+id/cardViewMuell"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="16dp"
app:cardCornerRadius="8dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingBottom="16dp">
<ImageView
android:id="#+id/imageViewMuellIcon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="16dp"
android:src="#drawable/ic_delete_black_24dp"
android:tint="#color/colorAccent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:text="Müll"
android:textColor="#000000"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="#+id/imageViewMuellIcon"
app:layout_constraintStart_toEndOf="#id/imageViewMuellIcon"
app:layout_constraintTop_toTopOf="#+id/imageViewMuellIcon"
app:layout_constraintVertical_bias="0.0" />
<ImageView
android:id="#+id/imageViewMuellExtend"
android:layout_width="30dp"
android:layout_height="30dp"
android:layout_margin="16dp"
android:background="#drawable/ic_keyboard_arrow_down_black_24dp"
app:layout_constraintBottom_toBottomOf="#+id/imageViewMuellIcon"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="#+id/imageViewMuellIcon" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/muell_extend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:visibility="gone"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#id/imageViewMuellIcon">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="#string/info_muell"
android:textColor="#000000"
android:textSize="18sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.cardview.widget.CardView>
Every CardView in this Fragment looks like this and the items are just renamed.
The first argument you're passing into TransitionManager.beginDelayedTransition is the sceneRoot. The transition will only affect views inside sceneRoot, nothing outside of it.
You're passing cardViewMuell as this argument, meaning the transition will animate views inside the clicked card, but none of the other cards. Try passing a sceneRoot that contains all of the cards.
I am trying to implement something like viewing a list of items in RecyclerView (id=schedule_recycler_view) which parent layout is a CardView (id = info_card_view). The Item is fetched by API call. If no item found, or connectivity issue, I want to view another layout (id = no_list_layout) which is Visibility-Gone at the first time.
But The problem I face, although I make the visibility of that layout (id = no_list_layout) visible programmatically, it did not visible.
Can anyone help?
Here the code what I tried
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:id="#+id/top_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="#dimen/_90sdp"
android:orientation="vertical"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toTopOf="#id/guideline">
<com.google.android.material.textview.MaterialTextView/>
<com.google.android.material.textview.MaterialTextView/>
<com.google.android.material.textview.MaterialTextView/>
</LinearLayout>
<androidx.constraintlayout.widget.Guideline
android:id="#+id/guideline"
android:layout_width="0dp"
android:layout_height="0dp"
android:orientation="horizontal"
app:layout_constraintGuide_begin="#dimen/_90sdp" />
<ImageView
android:id="#+id/add_schedule_image_view"
android:layout_width="#dimen/_50sdp"
android:layout_height="#dimen/_50sdp"
android:background="#drawable/circle_white_with_blue_border"
android:padding="#dimen/_5sdp"
android:src="#drawable/ic_plus"
app:layout_constraintBottom_toBottomOf="#id/guideline"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.9"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#id/guideline" />
<com.google.android.material.card.MaterialCardView
android:id="#+id/info_card_view"
style="#style/CardViewStyle"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:minHeight="#dimen/_200sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/top_bar_layout">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/schedule_recycler_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
<LinearLayout
android:id="#+id/no_list_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="#dimen/_15sdp"
android:orientation="vertical"
android:gravity="center"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/not_found_image_view"
android:layout_width="#dimen/_150sdp"
android:layout_height="#dimen/_150sdp"
tools:src="#drawable/ic_schedule"/>
<TextView
android:id="#+id/not_found_text_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
tools:text="No Invoice"
/>
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</com.google.android.material.card.MaterialCardView>
</androidx.constraintlayout.widget.ConstraintLayout>
in kotlin file
class TutorScheduleFragment : BaseFragment() {
private val tuitionScheduleAdapter by lazy {
TutorScheduleAdapter {
context?.showToast(it.day)
}
}
private val viewModel: TutorScheduleViewModel by lazy {
getViewModel {
TutorScheduleViewModel(
PreferenceService(context?.getSharedPreference()!!)
)
}
}
override fun getLayoutResId() = R.layout.fragment_tutor_schedule
override fun onResume() {
viewModel.getSchedule(jobTutorId!!)
}
override fun observeLiveData() {
viewModel.tuitionScheduleUiState.observe(this#TutorScheduleFragment, Observer {
it.getContentIfNotHandled()?.let { state ->
when (state) {
is Progress -> {
if (state.isLoading) {
} else {
}
}
is Success -> {
val schedules = state.successInfo.data
if (scheduleData.schedules.size == 0) {
no_list_layout.visibility = View.VISIBLE
} else {
tuitionScheduleAdapter.notifyChanged(scheduleData.schedules)
}
}
is Alert -> context?.showToast(state.alert)
is Failure -> {
if (state.throwable is IOException) {
context?.showToast("Internet Connection Failed")
} else {
context?.showToast("Json Parsing Error")
}
}
}
}
})
}
}
You should use no_list_layout.visibility = View.VISIBLE
Change your view visibility code
try this :
Kotlin:
if (list.size == 0) {
no_list_layout.visibility= View.VISIBLE
} else {
adapter.notifyChanged(list)
}
In Java
if (list.size == 0) {
no_list_layout.setVisibility(View.VISIBLE)
} else {
adapter.notifyChanged(list)
}
You can try with runOnUiThread.
runOnUiThread runs the specified action on the UI thread. If the
current thread is the UI thread, then the action is executed
immediately. If the current thread is not the UI thread, the action is
posted to the event queue of the UI thread.
context?.runOnUiThread(Runnable {
// Your Logic
if (list.size==0) {
no_list_layout.visibility= View.VISIBLE
} else {
// Your work
}
})
You have to hide your recyclerview also and make it visible in the other case like this:
if (scheduleData.schedules.size == 0) {
schedule_recycler_view.visibility = View.GONE
no_list_layout.visibility = View.VISIBLE
} else {
schedule_recycler_view.visibility = View.VISIBLE
no_list_layout.visibility = View.GONE
tuitionScheduleAdapter.notifyChanged(scheduleData.schedules)
}
At last, I found the actual culprit. It was in the layout file. I recreate the layout
<?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:id="#+id/info_card_view"
style="#style/CardViewStyle"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/white"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="1.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/top_bar_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#drawable/rectangle_light_blue_top_info_holder"
android:minHeight="#dimen/_90sdp"
android:orientation="vertical"
android:paddingTop="#dimen/_10sdp"
android:paddingBottom="#dimen/_10sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textview.MaterialTextView
android:id="#+id/upcoming_action_text_view"
style="#style/TextViewStyle.Bold"
android:text="Upcoming Test"
android:textSize="#dimen/_8ssp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<com.google.android.material.textview.MaterialTextView
android:id="#+id/date_text_view"
style="#style/TextViewStyle.Bold"
android:text="16 Aug, Wednesday"
android:textSize="#dimen/_15ssp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/upcoming_action_text_view" />
<ImageView
android:id="#+id/add_action_image_view"
android:layout_width="#dimen/_30sdp"
android:layout_height="#dimen/_30sdp"
android:src="#drawable/ic_plus"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.956"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.viewpager2.widget.ViewPager2
android:id="#+id/upcoming_action_view_pager"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:padding="#dimen/_20sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/date_text_view" />
<com.tbuonomo.viewpagerdotsindicator.WormDotsIndicator
android:id="#+id/dots_indicator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:dotsColor="#color/colorAccent"
app:dotsSize="#dimen/_8sdp"
app:dotsSpacing="#dimen/_2sdp"
app:dotsStrokeColor="#color/light_blue"
app:dotsStrokeWidth="#dimen/_1sdp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/upcoming_action_view_pager" />
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/previous_action_recycler_view"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="#dimen/_10sdp"
android:orientation="vertical"
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/top_bar_layout"
tools:itemCount="5"
tools:listitem="#layout/item_previous_action_of_confirm_job" />
<LinearLayout
android:id="#+id/no_list_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="vertical"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/top_bar_layout">
<ImageView
android:id="#+id/not_found_image_view"
android:layout_width="#dimen/_150sdp"
android:layout_height="#dimen/_150sdp"
android:src="#drawable/ic_schedule" />
<TextView
android:id="#+id/not_found_text_view"
style="#style/TextViewStyle.Center.Bold"
android:layout_marginTop="#dimen/_10sdp"
android:textColor="#color/colorTextSecondary"
android:text="No Invoice" />
</LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
I have one page called products. When page is loaded it shows productsfragment. This fragment has one RecyclerView which doesn't have any problem. On selecting a product a new fragment opens up and shows the list of product prices fragment. This fragment has one RecyclerView and the scrolling here doesn't works.
I tried gridview and cardview but they too are not scrolling. I tried gridview in scroll view or nested scroll view, they are also not scrolling.
here is my fragment with RecyclerView which is not scrolling
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/sorderfragment_step1_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".Activities.OrderSelect.Fragments.ProductSingleOrder.SOrderFragment_Step1">
<android.support.v7.widget.RecyclerView
android:id="#+id/gvProductPrices"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
and its my RecyclerView item view
<?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="200dp"
android:layout_height="200dp"
android:gravity="center"
android:maxHeight="200dp"
android:minHeight="200dp"
android:background="#layout/border2"
android:padding="0dp"
android:orientation="vertical">
<TextView
android:id="#+id/txtPriceName"
android:layout_width="match_parent"
android:layout_height="100dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:gravity="center"
android:text="Kucuk Boy Whopper"
android:textSize="30sp"
android:textStyle="bold"
app:layout_constraintBottom_toTopOf="#+id/constraintLayout4"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<android.support.constraint.ConstraintLayout
android:id="#+id/constraintLayout4"
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="0dp"
android:background="#000000"
app:layout_constraintBottom_toTopOf="#+id/txtPrice"
app:layout_constraintEnd_toEndOf="parent">
</android.support.constraint.ConstraintLayout>
<TextView
android:id="#+id/txtPrice"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="4dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:gravity="center"
android:text="14.99"
android:textColor="#000000"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" />
</LinearLayout>
and my adapter
class PriceAdapter(val priceList : List<ProductPrice>,
val context: Context) : RecyclerView.Adapter<ViewHolder>() {
override fun onCreateViewHolder(p0: ViewGroup, p1: Int): ViewHolder {
return ViewHolder(LayoutInflater.from(context).inflate(R.layout.gv_product_prices, p0, false))
}
override fun getItemCount(): Int {
return priceList.size
}
override fun onBindViewHolder(p0: ViewHolder, p1: Int) {
val price = priceList[p1]
p0.txtPriceName.text = price.getDescription()
p0.txtPriceName.isAllCaps = true
p0.txtPrice.text = BaseHelper.getNumericStr(price.getPrice())
}
}
class ViewHolder (view: View) : RecyclerView.ViewHolder(view) {
val txtPriceName = view.txtPriceName!!
val txtPrice = view.txtPrice!!
}
and my fragment code
class SOrderFragment_Step1 : Fragment() {
private var _priceRepository = ProductPriceRepository(OrderRepository.orderSelect!!)
private var priceAdapter: PriceAdapter? = null
private var prices: List<ProductPrice>? = null
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.fragment_sorder_step1, container, false)
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
configurePrices()
}
private fun configurePrices() {
prices = _priceRepository.getPriceByProductId(OrderRepository.currentProduct!!.getId())
gvProductPrices.layoutManager = GridLayoutManager(OrderRepository.orderSelect!!, 2)
gvProductPrices.adapter = PriceAdapter(prices!!, this, OrderRepository.orderSelect!!)
}
fun priceSelect(price: ProductPrice) {
Toast.makeText(OrderRepository.orderSelect!!, price.getDescription(), Toast.LENGTH_LONG).show()
}
}
and also fragment change like this
val manager = this.fragmentManager!!.beginTransaction()
manager.setCustomAnimations(android.R.anim.fade_in, android.R.anim.fade_out)
manager.replace(R.id.fragmentProductSteps, SOrderFragment_Step1(), "detailFragment").commit()
and fragment base activity xml
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.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"
android:id="#+id/order_select_layout"
tools:context=".OrderSelect">
<GridView
android:id="#+id/gvProductGroups"
android:layout_width="165dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
android:scrollbars="none"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/linearLayout" />
<LinearLayout
android:id="#+id/linearLayout"
android:layout_width="0dp"
android:layout_height="225dp"
android:orientation="horizontal"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<android.support.constraint.ConstraintLayout
android:layout_width="0dip"
android:layout_height="match_parent"
android:layout_weight="7">
<include
layout="#layout/activity_advertise_partition"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</LinearLayout>
<LinearLayout
android:id="#+id/orderProductLayout"
android:layout_width="0dp"
android:layout_height="83dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:background="#layout/gv_order_products_border"
android:orientation="vertical"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/btnCancelCurrentOrder2"
app:layout_constraintStart_toEndOf="#+id/gvProductGroups">
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginLeft="20dp"
android:layout_marginTop="5dp"
android:id="#+id/paymentView"
android:layout_marginRight="5dp"
android:layout_marginBottom="5dp"
android:layout_weight="1">
<TextView
android:id="#+id/txtTotalL"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="TOPLAM :"
android:textColor="#bc3030"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<TextView
android:id="#+id/txtPriceL"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="-1dp"
android:layout_weight="1"
android:gravity="left|center"
android:text="₺ 0.00"
android:textColor="#000000"
android:textSize="24sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/imgOrderButton"
app:layout_constraintStart_toEndOf="#+id/txtTotalL"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.0" />
<Button
android:id="#+id/imgOrderButton"
android:layout_width="175dp"
android:layout_height="0dp"
android:layout_marginBottom="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:background="#15912e"
android:padding="15sp"
android:text="Sepeti Goster"
android:textColor="#FFFFFF"
android:textSize="18sp"
android:textStyle="bold"
android:visibility="invisible"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
</LinearLayout>
<fragment
android:id="#+id/fragmentProductSteps"
android:name="com.example.alknakralar.kios.Helpers.BlankFragment"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginStart="24dp"
android:layout_marginLeft="24dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="24dp"
android:layout_marginRight="24dp"
android:layout_marginBottom="8dp"
app:layout_constraintBottom_toTopOf="#+id/orderProductLayout"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="#+id/gvProductGroups"
app:layout_constraintTop_toBottomOf="#+id/linearLayout" />
<Button
android:id="#+id/btnCancelCurrentOrder2"
android:layout_width="125dp"
android:layout_height="0dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="8dp"
android:background="#ff0000"
android:text="SEPETI BOSALT"
android:textColor="#FFFFFF"
android:textSize="24sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="#+id/imgBackFromProducts"
app:layout_constraintTop_toBottomOf="#+id/fragmentProductSteps" />
<ImageView
android:id="#+id/imgBackFromProducts"
android:layout_width="70dp"
android:layout_height="0dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#+id/fragmentProductSteps"
app:srcCompat="#drawable/back" />
</android.support.constraint.ConstraintLayout>
How can i fix this issue ?
Sugession: Why are you using grid view and setting adapter to it where you have another approach and commonly used approach.
Which is to use recycler view and set its layout manager as GridLayout manager
Below single line will make your job done
recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));