I created a custom view, and tried to restore the state automatically on screen rotation (just as EditText restores current input text automatically), but when I see the log, onSaveInstanceState is not called, and only onRestoreInstanceState is called. What is wrong?
class MyView:LinearLayout
{
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context?, attrs: AttributeSet?, defStyleAttr: Int) : super(
context, attrs, defStyleAttr)
init
{
isSaveEnabled=true
}
override fun onSaveInstanceState(): Parcelable
{
return super.onSaveInstanceState()
Log.d("ss", "save")
}
override fun onRestoreInstanceState(state: Parcelable?)
{
super.onRestoreInstanceState(state)
Log.d("ss", "restore")
}
}
Activity layout:
<?xml version="1.0" encoding="utf-8"?>
<AbsoluteLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/top"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.loser.mylayouttest.MyView
android:id="#+id/myView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</AbsoluteLayout>
Activity:
class MainActivity : AppCompatActivity()
{
override fun onCreate(savedInstanceState: Bundle?)
{
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
The reason why you can't see Log.d("ss", "save") being called is simply that the code line is invoked after the return statement. The onSaveInstanceState() is actually called. To see the log move Log.d("ss", "save") above return super.onSaveInstanceState().
Related
I have:
class MainBottomNavigation : BottomNavigationView {
private var navController: NavController? = null
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(
context,
attrs,
defStyleAttr
)
init {
setUpListeners()
}
private fun setUpListeners() {
setOnItemSelectedListener { menuItem ->
when (menuItem.itemId) {
R.id.fragment_navigation_one-> {
...
true
}
R.id.fragment_navigation_two-> {
...
true
}
else -> false
}
}
setOnItemReselectedListener {
}
}
fun setupWithNavController(navController: NavController) {
this.navController = navController
NavigationUI.setupWithNavController(this, navController)
}
}
In the AndroidManifest I have:
<activity
android:name=".presentation.MainActivity"
android:exported="true"
<nav-graph android:value="#navigation/main_navigation" />
</activity>
and in the layout of the main activity I have:
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/main_navigation" />
While the OnItemReselectedListener is called and everything works as expected that means that nothing happens on reselecting, the OnItemSelectedListener is never called.
The reason why I need the listener is that by default the BottomNavigationView creates new fragments and replaces the previous ones instead of reusing the fragment that are already there. I have seen people suggesting to create instances of the Fragments and then reuse them in the listener.
What I wanted to try was to use the listener to check whether the Fragment is already there and eventually hide the current (to be able to show it again later) and show the new one.
I am writing a WebRTC solution and having an issue in Local View while using back camera (Wrong Rotation / Incorrect View)
<com.src.webrtc.android.VideoView
android:id="#+id/main_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content" />
Local View (Incorrect view)
Remote View (Correct View : while viewing as a Remote user)
I was facing the same issue while working on the webRTC. I fixed it by setting the method setMirror(false).
here's some code:
call_activity.xml
<org.webrtc.SurfaceViewRenderer
android:id="#+id/fullscreen_video_view"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center" />
<org.webrtc.SurfaceViewRenderer
android:id="#+id/pip_video_view"
android:layout_height="144dp"
android:layout_width="wrap_content"
android:layout_gravity="bottom|end"
android:layout_margin="16dp"/>
in CallActivity.java
SurfaceViewRenderer fullscreenRenderer =
findViewById(R.id.fullscreen_video_view);
fullscreenRenderer.init(eglBase.getEglBaseContext(), null);
fullscreenRenderer.setScalingType(ScalingType.SCALE_ASPECT_FILL);
fullscreenRenderer.setEnableHardwareScaler(false /* enabled */);
//this code is used for rotation
fullscreenRenderer.setMirror(false);
I am using implementation 'org.webrtc:google-webrtc:1.0.28513'
Update:
what you can do in VideoView.kt is:
class VideoView : SurfaceViewRenderer{
constructor(context: Context) : super(context)
constructor(context: Context, attrs: android.util.AttributeSet?) : super(context, attrs)
fun init(rendererEvents: RendererCommon.RendererEvents?) {
super.init(EglBaseProvider.getEglBase(this).eglBaseContext, rendererEvents)
setMirror(false)
}
override fun release() {
super.release()
EglBaseProvider.release(this)
}
override fun setMirror(mirror: Boolean) {
super.setMirror(mirror)
}
}
or
class VideoView : SurfaceViewRenderer{
constructor(context: Context) : super(context)
constructor(context: Context, attrs: android.util.AttributeSet?) : super(context, attrs)
fun init(rendererEvents: RendererCommon.RendererEvents?) {
super.init(EglBaseProvider.getEglBase(this).eglBaseContext, rendererEvents)
super.setMirror(false)
}
override fun release() {
super.release()
EglBaseProvider.release(this)
}
}
In Android, I have two class files, MainActivity and CanV.
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
}
}
CanV.kt, This is a View class.
class CanV(context: Context, attributeSet: AttributeSet): View(context){ ... }
CanV view in activity_main.xml
<com.app.app_name.CanV
android:id="#+id/cans"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginBottom="60dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="1.0">
</com.app.app_name.CanV>
Now I want to create CanV class object in MainActivity.
I came to try:
val c: CanV = CanV(this, ?)
But, I don't know the AttributeSet parameter value. How do I create and pass the AttributeSet of CanV view?
If you want to be able to create instances of CanV from both XML and Java/Kotlin, you should provide two constructors:
class CanV : View {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
...
}
The first can be used from Kotlin (val v: CanV = CanV(this)), and the second is used automatically when inflating from XML.
Problem with inflating custom ViewGroup.
Unable to start activity
Binary XML file line #14: Binary XML file line #14: Error inflating class com.example.interactiveplatform.view.GraphLayout.
I searched about this problem and there is something wrong with constructors.
<LinearLayout
android:id="#+id/graph"
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"
android:orientation="horizontal"
tools:context=".MainActivity">
<com.example.interactiveplatform.view.GraphLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
</com.example.interactiveplatform.view.GraphLayout>
</LinearLayout>
class GraphLayout(context: Context, attrs: AttributeSet, var chapterAdapter: ChapterAdapter) : ViewGroup(context, attrs) {
private val detector: GestureDetector
private val mMoveAndScaleHandler: MoveAndScaleHandler
private val myListener: GestureDetector.SimpleOnGestureListener
private var spacing = 0
init {
myListener = object : GestureDetector.SimpleOnGestureListener() {
override fun onDown(e: MotionEvent?): Boolean {
return true
}
}
detector = GestureDetector(context, myListener)
mMoveAndScaleHandler = MoveAndScaleHandler(context, this, chapterAdapter)
}
override fun onLayout(p0: Boolean, p1: Int, p2: Int, p3: Int, p4: Int) {
for(i in 0 until childCount){
val v = getChildAt(i)
v.layout(v.left, v.top, v.right, v.bottom)
}
}
override fun onTouchEvent(event: MotionEvent): Boolean {
detector.onTouchEvent(event)
invalidate()
return mMoveAndScaleHandler.onTouchEvent(event)
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(400 * chapterAdapter.numberChapters,chapterAdapter.heightScreen)
}
}
When you instantiate your custom view via XML you cannot pass custom constructor parameters like chapterAdapter. Also, you have to support all Android's view constructors. For example, you can do it like this:
class GraphLayout #JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : ViewGroup(context, attrs, defStyleAttr)
I have 2 fragments inside the NestedScrollView and one fragment contains RecyclerView and another fragment contains GoogleMap and each fragment contains a text view as a title on top of it.
When I long tap on recycler view I am showing recycler view in full-screen view by changing its height to 100%.
Now I want to stop scrolling the title of RecyclerView's fragment but it is still scrolling the title when recycler view reached its last item.
This is the layout:
<?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="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<com.myapp.common.CustomNestedScrollView
android:id="#+id/nestedScrollView"
android:layout_width="match_parent"
android:layout_height="match_parent">
<FrameLayout
android:id="#+id/container"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animateLayoutChanges="true" />
</com.myapp.common.CustomNestedScrollView>
</LinearLayout>
It looks like:
I tried to stop the scrolling by extending the CustomNestedScrollView with NestedScrollView like:
class CustomNestedScrollView : NestedScrollView {
var isEnableScrolling = true
constructor(context: Context, attrs: AttributeSet, defStyle: Int) : super(context, attrs, defStyle) {}
constructor(context: Context, attrs: AttributeSet) : super(context, attrs) {}
constructor(context: Context) : super(context) {}
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
return if (isEnableScrolling) {
super.onInterceptTouchEvent(ev)
} else {
false
}
}
override fun onTouchEvent(ev: MotionEvent): Boolean {
return if (isEnableScrolling) {
super.onTouchEvent(ev)
} else {
false
}
}
}
And setting the value from the activity when height is 100% like:
nestedScrollView.isEnableScrolling = !isFull
Also tried by stopping Scroll of NestedScrollView like:
if (isFull) {
nestedScrollView.stopNestedScroll(ViewCompat.TYPE_NON_TOUCH)
} else {
nestedScrollView.startNestedScroll(ViewCompat.SCROLL_AXIS_VERTICAL, ViewCompat.TYPE_TOUCH)
}
Expected: