I am trying to change width of a view programmatically, but it doesn't work, nothing changes. This is the code:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/myFragmentLayout"
android:layout_width="wrap_content"
android:layout_height="50dp"
android:orientation="horizontal">
<View
android:id="#+id/myView"
android:layout_width="10dp"
android:layout_height="50dp" />
And in my fragment, I try this:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
val views = FragmentMyBinding.bind(view)
views.myView.layoutParams.width = 500
I tried using viewTreeObserver, but still nothing happens:
views.myView.viewTreeObserver.addOnGlobalLayoutListener(
object : OnGlobalLayoutListener {
override fun onGlobalLayout() {
view.viewTreeObserver
.removeOnGlobalLayoutListener(this)
views.myView.updateLayoutParams {
width = 500
}
}
})
Seems like I am calling layoutParams on a wrong layout for some reason
Try this
val params: LinearLayout.LayoutParams = views.myView.layoutParams as LinearLayout.LayoutParams
params.width = 500
views.myView.layoutParams = params
Related
I want to move a ConstraintLayout programmatically. I looked through some solutions on stack overflow but they didn't work for me.
There are two ConstraintLayouts placed vertically. When the code goes into else if("android.permission.CAMERA" in permissionList.toString(), the above constraint layout (layoutLocation) will be invisible and the below constraint layout (layoutCamera) will come up and take its position. I mark where I should use declare it with 'want to use here'.
Code (apology to not ba able to post the whole code due to patent reason)
class SplashFragment : Fragment() {
private lateinit var mContext: MainActivity
private lateinit var binding : FragmentSplashBinding
private val viewModel : SplashViewModel by inject()
private val getPermissionUseCase : GetPermissionUseCase by inject()
override fun onAttach(context: Context) {
super.onAttach(context)
mContext = context as MainActivity
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_splash, container, false)
return binding.root
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.viewModel = viewModel
binding.lifecycleOwner = viewLifecycleOwner
}
private fun actionApplicationSetting(permissionList : List<String>) {
val layoutInflater = LayoutInflater.from(context)
val view = layoutInflater.inflate(R.layout.dialog_splash, null)
val alertDialog = AlertDialog.Builder(requireContext(), R.style.CustomAlertDialog).setView(view).create()
val layoutLocation : ConstraintLayout = view.findViewById(R.id.layout_box_location)
val layoutCamera : ConstraintLayout = view.findViewById(R.id.layout_box_camera)
for(permission in permissionList) {
if("android.permission.CAMERA" in permissionList.toString() && "android.permission.ACCESS_COARSE_LOCATION" in permissionList.toString()) {
layoutLocation.background = AppCompatResources.getDrawable(mContext, R.drawable.auth_level_blue)
layoutCamera.background = AppCompatResources.getDrawable(mContext, R.drawable.auth_level_blue)
}else if("android.permission.ACCESS_COARSE_LOCATION" in permissionList.toString()) {
layoutLocation.background = AppCompatResources.getDrawable(mContext, R.drawable.auth_level_blue)
}else if("android.permission.CAMERA" in permissionList.toString()) {
layoutLocation.visibility = View.INVISIBLE
// want to use here
}
}
alertDialog.show()
}
}
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:id="#+id/layout_main"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="wrap_content"
android:layout_height="60dp"
android:layout_marginStart="70dp"
android:layout_marginBottom="10dp"
app:layout_constraintBottom_toBottomOf="#+id/layout_wrapper"
app:layout_constraintEnd_toEndOf="#+id/layout_wrapper"
app:layout_constraintStart_toStartOf="#+id/layout_wrapper">
</androidx.constraintlayout.widget.ConstraintLayout>
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_wrapper"
android:layout_width="match_parent"
android:layout_height="180dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_box_location"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<androidx.constraintlayout.widget.ConstraintLayout
android:id="#+id/layout_box_camera"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/layout_box_location" />
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Instead of layoutLocation.visibility = View.INVISIBLE try layoutLocation.visibility = View.GONE
I've created a basic layout in Android in my activity_main.xml for what will eventually be a custom view for a button. It is a relative view with three circles stacked on top of eachother inside it aligned in the centre. The circles change size when the user interacts with them.
I now want to replicate the whole thing purely in Kotlin code, as it will be loaded using data in a database.
I can't figure it out. Heres the manifest...
<?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:gravity="center"
android:orientation="vertical"
tools:context=".MainActivity">
<RelativeLayout
android:id="#+id/myContainer"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<ImageView
android:id="#+id/button3"
android:layout_width="400dp"
android:layout_height="400dp"
android:layout_centerInParent="true"
app:srcCompat="#drawable/circle"
app:tint="#E60505" />
<ImageView
android:id="#+id/button2"
android:layout_width="400dp"
android:layout_height="400dp"
android:layout_centerInParent="true"
app:srcCompat="#drawable/circle"
app:tint="#FFB700" />
<ImageView
android:id="#+id/button1"
android:layout_width="60dp"
android:layout_height="60dp"
android:layout_alignParentRight="false"
android:layout_centerInParent="true"
app:srcCompat="#drawable/circle" />
</RelativeLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
Then in Kotlin, all I can find about is LayoutParams for width and height, but where do I set all this stuff for the Relative Layout?
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
which I presume I want to do something like:
class MyContainer : RelativeLayout () {
var button1 = MyButtonClass(someArgs)
var button2 = MyButtonClass(someArgs)
var button3 = MyButtonClass(someArgs)
init {
/// can't find out how to do this bit in Kotlin...
///something like....
this.layoutParams.width = ViewGroup.LayoutParams.MATCH_PARENT
this.layoutConstraintBottomToBottomOf = PARENT
this.layoutConstraintHorizontalBias = 0.5
///etc...
//then add the circle buttons
this.addView(button3)
this.addView(button2)
this.addView(button1)
}
}
Am I even vagueley on the right track? Any pointers would be really appreciated.
EDIT: Following first answer, I can set layout attributes, but my app is just blank when i try to reproduce my original manifest tree in code. Have I applied this correctly?
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val appContainer = findViewById<ConstraintLayout>(R.id.appContainer)
var buttonContainer = ButtonContainer(this.applicationContext)
appContainer.addView(buttonContainer)
}
}
class ButtonContainer (context: Context) : RelativeLayout(context) {
var button1 = CustomButton(context)
val buttonLayoutParams by lazy { ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT).apply {
bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
startToStart = ConstraintLayout.LayoutParams.PARENT_ID
topToTop = ConstraintLayout.LayoutParams.PARENT_ID
endToEnd = ConstraintLayout.LayoutParams.PARENT_ID
horizontalBias = 0.5F
}
}
override fun onFinishInflate() {
super.onFinishInflate()
this.layoutParams = buttonLayoutParams
this.addView(button1)
}
}
class CustomButton(context: Context) : ImageView(context) {
val layoutParams by lazy { RelativeLayout.LayoutParams(60, 60).apply {
addRule(RelativeLayout.CENTER_IN_PARENT, RelativeLayout.TRUE)
}
}
override fun onFinishInflate() {
super.onFinishInflate()
setLayoutParams(layoutParams)
setBackgroundResource(squibcircle)
}
}
You need to cast LayoutParams as ConstraintLayout.LayoutParams to set those properties like below
class ButtonContainer(context: Context) : RelativeLayout(context) {
var button1 = CustomButton(context)
val buttonLayoutParams by lazy { ConstraintLayout.LayoutParams(ConstraintLayout.LayoutParams.WRAP_CONTENT, ConstraintLayout.LayoutParams.WRAP_CONTENT).apply {
bottomToBottom = ConstraintLayout.LayoutParams.PARENT_ID
startToStart = ConstraintLayout.LayoutParams.PARENT_ID
topToTop = ConstraintLayout.LayoutParams.PARENT_ID
endToEnd = ConstraintLayout.LayoutParams.PARENT_ID
horizontalBias = 0.5F
}
}
override fun onFinishInflate() {
this.layoutParams = buttonLayoutParams
this.addView(button1)
}
}
i have the xml with recyclerview, id = list_chat
<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=".ui.chats.ChatsFragment">
<androidx.recyclerview.widget.RecyclerView
android:id="#+id/list_chat"
android:layout_width="match_parent"
android:layout_height="match_parent">
</androidx.recyclerview.widget.RecyclerView>
</androidx.constraintlayout.widget.ConstraintLayout>
my Fragment where will be recyclerview with function uploadList which put data in my array for recyclerView
class ChatsFragment : Fragment() {
var list: MutableList<Chat> = ArrayList()
lateinit var adapter: ChatListAdapter
lateinit var manager: RecyclerView.LayoutManager
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
uploadList()
Log.e("TAG", list.toString())
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
val view: View = inflater.inflate(R.layout.fragment_chats, container, false)
uploadList()
manager = LinearLayoutManager(activity)
list_chat.layoutManager = manager
adapter = ChatListAdapter(list)
list_chat.adapter = adapter
return view
}
private fun uploadList(){
list.add(Chat("11111", "11111"))
list.add(Chat("11222221", "133311"))
list.add(Chat("1122221", "114444411"))
list.add(Chat("112222211", "5555555"))
}
}
xml with item for list. ImageView is no matter for now. Need only two textView
<?xml version="1.0" encoding="utf-8"?>
<layout
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/item_list"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<de.hdodenhof.circleimageview.CircleImageView
android:id="#+id/chatImage"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="#mipmap/ic_launcher"/>
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
android:layout_marginStart="5sp">
<TextView
android:id="#+id/nameChat"
android:text="2222222222222"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="#+id/infoChat"
android:text="11111111"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
</LinearLayout>
</layout>
and my custom Adapter
class ChatListAdapter(private val myDataset: MutableList<Chat>) :RecyclerView.Adapter<ChatListAdapter.ViewHolder>() {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val layoutInflater = LayoutInflater.from(parent.context)
.inflate(R.layout.item_list, parent, false)
return ViewHolder(layoutInflater)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(myDataset[position])
}
override fun getItemCount() = myDataset.size
class ViewHolder(v: View) : RecyclerView.ViewHolder(v){
private val nameChat: TextView = itemView.findViewById(R.id.nameChat)
private val infoChat: TextView = itemView.findViewById(R.id.infoChat)
fun bind(chat: Chat){
nameChat.text = chat.name
infoChat.text = chat.info
}
}
}
and i catch java.lang.IllegalStateException: list_chat must not be null here list_chat.layoutManager = manager
help me with it, i have list_chat only in fragment_chats, so it is right recyclerview.
Because help me pls, I dont know what is the problem
Initialize layout manager and adapter in onViewCreated() Method
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
uploadList()
manager = LinearLayoutManager(activity)
list_chat.layoutManager = manager
adapter = ChatListAdapter(list)
list_chat.adapter = adapter
})
Are you using kotlinx.android.synthetic to find your views? If so, these are not valid until after onCreateView() returns, and so you cannot use them within onCreateView().
Move your code to onViewCreated(), or switch to manually calling view.findViewById() from inside onCreateView().
Approach 1 :
Create a recyclerview object :
val rv = view.findViewById(your rv id)
and assign the layout manager and adapter to it.
Approach 2 :
In your layout file, in recyclerview add this line :
<androidx.recyclerview.widget.RecyclerView
<!-- your default lines -->
app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager"
/>
and assign the adapter in onViewCreated method.
I've followed this tutorial to implement BottomSheetDiaogFragment in my android application.
this is my bottom sheet layout (bottom_sheet.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"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RadioGroup
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
android:layout_marginBottom="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<RadioButton
android:id="#+id/rb1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:text="#string/rb1" />
<RadioButton
android:id="#+id/rb2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_weight="1"
android:text="#string/rb2" />
</RadioGroup>
</android.support.constraint.ConstraintLayout>
BottomSheetDialogFragment class:
class BottomSheetTaskRepeat : BottomSheetDialogFragment() {
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
return inflater.inflate(R.layout.bottom_sheet, container, false)
}
}
activity:
private val bottomSheetTaskRepeat = BottomSheetTaskRepeat()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
bottomSheetTaskRepeat.show(supportFragmentManager, "my_bottom_sheet")
}
The problem is that the bottom sheet is not showing up! Any help is appreciated.
This is a late Answer, I am writing for anyone who will face the same problem, This is what I found:
For some reasons non-constrained views heights do not work in BottomSheetDialogFragment. A view whose height is like wrap_content will not show.(But the shadow will be there), but when you specify its height like 80dp it works.
For this question go and change your RadioGroup height and specify it like to:
android:layout_height="200dp"
Hope that is helpful.
UPDATE:
Since the default container of BottomSheetDailogFragment is FrameLayout and is set to WRAP_CONTENT, You can override that on your Fragment onStart method like this (Kotlin):
override fun onStart() {
super.onStart()
val containerID = com.google.android.material.R.id.design_bottom_sheet
val bottomSheet: FrameLayout? = dialog?.findViewById(containerID)
bottomSheet?.let {
BottomSheetBehavior.from<FrameLayout?>(it).state =
BottomSheetBehavior.STATE_HALF_EXPANDED
bottomSheet.layoutParams.height = FrameLayout.LayoutParams.MATCH_PARENT
}
view?.post {
val params = (view?.parent as View).layoutParams as (CoordinatorLayout.LayoutParams)
val behavior = params.behavior
val bottomSheetBehavior = behavior as (BottomSheetBehavior)
bottomSheetBehavior.peekHeight = view?.measuredHeight ?: 0
(bottomSheet?.parent as? View)?.setBackgroundColor(Color.TRANSPARENT)
}
}
Try following:
Create and use the parameterless static method newInstance in your BottomSheetDialogFragment and call the show() method on it.
Try LinearLayoutCompat as a root layout instead of ConstraintLayout.
Try a colourful background to the root layout to get an idea.
Try match_parent height for the root layout.
Make sure that the dismiss() or cancel() is not being called on it immediately.
Check visibility.
If it contains a recyclerView, make sure that it has items, getItemCount is not returning 0, and that we are setting up the values properly!
Restart both: PC and Device if your changes are not reflecting because of Android Studio errors.
Instead of using supportFragmentManager you have to use childFragmentManager,if you are inflating from inner fragments.
private val bottomSheetTaskRepeat = BottomSheetTaskRepeat()
bottomSheetTaskRepeat.show(childFragmentManager, "my_bottom_sheet")
I'm trying to implement the same behaviour than the CollapsingToolbarLayout for a view above my recyclerview that collapses to a minimum height on downscrolling and restores to its normal height when the scroll reaches the top. This header is not a Toolbar, hence the custom view.
I managed to do it, but when scrolling up it restores the height but the whole view starts flickering.
This is the header layout, I am trying to make the Textview disappear while keeping the inner linear layout visible at all times:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:gravity="center">
<TextView
android:id="#+id/welcome_message"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="12dp"
android:text="welcome"/>
<LinearLayout
android:id="#+id/always_show"
android:layout_width="match_parent"
android:layout_height="36dp"
android:orientation="horizontal"
android:gravity="center_vertical"
android:layout_margin="12dp">
...
</LinearLayout>
</LinearLayout>
And this is the code
var maxHeight: Int = 0
var initialSize = false
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
...
header.getViewTreeObserver().addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
if (initialSize)
return
initialSize = true
maxHeight = header.measuredHeight
}
})
recyclerView.addOnScrollListener(object: RecyclerView.OnScrollListener() {
override fun onScrolled(recyclerView: RecyclerView?, dx: Int, dy: Int) {
super.onScrolled(recyclerView, dx, dy)
if (dy > 0) {
//scroll down
val params = header.layoutParams as LinearLayout.LayoutParams
params.topMargin = Math.max(params.topMargin-dy, -maxHeight/2)
header.layoutParams = params
} else if (layoutManager.findFirstCompletelyVisibleItemPosition() == 0) {
//top
val params = header.layoutParams as LinearLayout.LayoutParams
params.topMargin = 0
header.layoutParams = params
}
}
})
}
Any ideas on how to make this animation more natural, closest to the CollapsingToolbarLayout behaviour.