Data binding: Not call onClick method - android-databinding

Android 4.3+
I trt to use data binding. I use official documentation from here Data binding
So in app/build.gradle:
dataBinding {
enabled = true
}
In my xml layout file:
<layout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<data>
<variable
name="handler"
type="com.myproject.SettingsFragment" />
</data>
<android.support.constraint.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent" >
<FrameLayout
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.constraint.ConstraintLayout
android:id="#+id/contentContainer"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.ConstraintLayout
android:id="#+id/contactUsContainer"
android:layout_width="match_parent"
android:onClick="#{handler::onClickContactUs}">
<TextView
android:id="#+id/contactUsTextView"
android:layout_width="0dp"
android:layout_height="wrap_content"/>
</android.support.constraint.ConstraintLayout>
</android.support.constraint.ConstraintLayout>
</FrameLayout>
</ScrollView>
</android.support.constraint.ConstraintLayout>
</layout>
And here my fragment SettingsFragment.java:
public class SettingsFragment extends Fragment {
#Nullable
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.settings, container, false);
return rootView;
}
public void onClickContactUs(View view) {
}
}
But when I click on container contactUsContainer the method onClickContactUs() is NOT call.
Why?

You're experiencing a common problem. First, you must inflate the binding using the binding inflate() call. Second, you must set the binding variables:
#Override
public View onCreateView(LayoutInflater inflater, #Nullable ViewGroup container, #Nullable Bundle savedInstanceState) {
MyLayoutBinding binding = MyLayoutBinding.inflate(inflater, container, false);
binding.setHandler(this);
return binding.getRoot();
}

#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
userDetailViewBinding=DataBindingUtil.inflate(inflater,R.layout.fragment_user_detail_view, container, false);
ProfileViewModel.Factory factory = new ProfileViewModel.Factory(getActivity().getApplication());
viewModel = ViewModelProviders.of(this, factory)
.get(ProfileViewModel.class);
observeViewModel(viewModel);
userDetailViewBinding.setProfileViewModel(viewModel);
userDetailViewBinding.setUserDetailViewFrag(this);
return userDetailViewBinding.getRoot();
}

Related

Fragment displaying a grey field

I am still a bit new to fragments in android studio but I was wondering if this is usually how fragments are displayed as on the phone. It appear as a grey background above my activity, as shown in this image: https://gyazo.com/9d5569718c5092debfeaab1c631b0046
This is my MainAppActivity code:
class MainAppActivity : AppCompatActivity() {
private lateinit var appBarConfiguration: AppBarConfiguration
private lateinit var binding: ActivityMainAppBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainAppBinding.inflate(layoutInflater)
setContentView(binding.root)
setSupportActionBar(binding.appBarMainApp.toolbar)
binding.appBarMainApp.fab.setOnClickListener { view ->
Snackbar.make(view, "Replace with your own action", Snackbar.LENGTH_LONG)
.setAction("Action", null).show()
}
val drawerLayout: DrawerLayout = binding.drawerLayout
val navView: NavigationView = binding.navView
val navController = findNavController(R.id.nav_host_fragment_content_main_app)
// Passing each menu ID as a set of Ids because each
// menu should be considered as top level destinations.
appBarConfiguration = AppBarConfiguration(
setOf(
R.id.nav_home, R.id.nav_gallery, R.id.nav_slideshow
), drawerLayout
)
setupActionBarWithNavController(navController, appBarConfiguration)
navView.setupWithNavController(navController)
}
override fun onCreateOptionsMenu(menu: Menu): Boolean {
// Inflate the menu; this adds items to the action bar if it is present.
menuInflater.inflate(R.menu.main_app, menu)
return true
}
override fun onSupportNavigateUp(): Boolean {
val navController = findNavController(R.id.nav_host_fragment_content_main_app)
return navController.navigateUp(appBarConfiguration) || super.onSupportNavigateUp()
}
}
Any buttons or similar seems to also be affected by it.
Is this normal or is it some sort of bug?
My content_main_app, this is my home set fragment:
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main_app">
<fragment
android:id="#+id/nav_host_fragment_content_main_app"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</androidx.constraintlayout.widget.ConstraintLayout>
Fragment 1:
class HomeFragment : Fragment() {
private lateinit var binding: FragmentHomeBinding
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
// Inflate the layout for this fragment
binding = DataBindingUtil.inflate(inflater, R.layout.fragment_home, container, false)
return binding.root
}
}
XML layout fragment 1:
<?xml version="1.0" encoding="utf-8"?>
<layout>
<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=".HomeFragment"
android:background="#android:color/transparent"
>
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_height="match_parent"
android:layout_width="match_parent"
/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Fragment 2:
class HobbiesFragment : Fragment() {
private var _binding: FragmentHobbiesBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val hobbiesViewModel =
ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentHobbiesBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView: TextView = binding.mainTitle
hobbiesViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
XML layout fragment 2:
<?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">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/beige1"
tools:context=".ui.Hobbies.HobbiesFragment">
<!-- TODO: Update blank fragment layout -->
<TextView
android:id="#+id/mainTitle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="HOBBIES"
android:textColor="#color/blueMix"
android:textSize="38sp"
android:textStyle="bold"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.043" />
<Button
android:id="#+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.097"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/mainTitle"
app:layout_constraintVertical_bias="0.064" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Fragment 3:
class GalleryFragment : Fragment() {
private var _binding: FragmentGalleryBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(
inflater: LayoutInflater,
container: ViewGroup?,
savedInstanceState: Bundle?
): View {
val galleryViewModel =
ViewModelProvider(this).get(GalleryViewModel::class.java)
_binding = FragmentGalleryBinding.inflate(inflater, container, false)
val root: View = binding.root
val textView: TextView = binding.textGallery
galleryViewModel.text.observe(viewLifecycleOwner) {
textView.text = it
}
return root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
}
XML layout fragment 3:
<?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=".ui.gallery.GalleryFragment">
<TextView
android:id="#+id/text_gallery"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:layout_marginEnd="8dp"
android:textAlignment="center"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
After a few hours of messing around in android studio I finally found out what was giving me a grey background, covering the main fragment. I had to go into my main activity ( mainAppActivity in my case ) and delete the material divider (as seen in the image). It solved the problem for me.

How to find a view for Snackbar in fragment's onCreateView method if I use view binding and navigation component?

I'm trying to show a snack bar in fragment's onCreateView method but I don't know what view to passing inside the snack bar.
I'm very confused because I first time use the Navigation component and view binding and maybe is there a problem.
I tried binding.root but I got this exception:
java.lang.IllegalArgumentException: No suitable parent found from the
given view. Please provide a valid view.
After that I tried requireView().rootView as parameter but I also got this exception:
java.lang.IllegalStateException: Fragment XFragment{7a091b5}
(cefa1aef-59c3-4602-bcf1-b36f7d538cf9) id=0x7f0800f7} did not return a
View from onCreateView() or this was called before onCreateView()
MY CODE IN XFragment:
package com.sdsd.sds
import android.os.Bundle
import androidx.fragment.app.Fragment
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import androidx.navigation.Navigation
import com.google.android.material.snackbar.Snackbar
import com.sdsd.sds.databinding.FragmentXBinding
private const val ARG_PARAM1 = "param1"
private const val ARG_PARAM2 = "param2"
class XFragment : Fragment() {
private var _binding: FragmenXBinding? = null
private val binding get() = _binding!!
private var param1: String? = null
private var param2: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
arguments?.let {
param1 = it.getString(ARG_PARAM1)
param2 = it.getString(ARG_PARAM2)
}
}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentXBinding.inflate(inflater, container, false)
binding.tvFgRegistration.setOnClickListener {
Navigation.findNavController(binding.root)
.navigate(R.id.action_f1_to_f2)
}
val snackbar: Snackbar = Snackbar.make(binding.root, "Succesful", Snackbar.LENGTH_LONG)
snackbar.show()
return binding.root
}
override fun onDestroyView() {
super.onDestroyView()
_binding = null
}
companion object {
#JvmStatic
fun newInstance(param1: String, param2: String) =
XFragment().apply {
arguments = Bundle().apply {
putString(ARG_PARAM1, param1)
putString(ARG_PARAM2, param2)
}
}
}
}
XML LAYOUT FILE:
<?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="#drawable/ic"
tools:context=".XFragment">
<EditText
android:id="#+id/etE"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:background="#color/translucent"
android:drawableStart="#drawable/ic_vector"
android:drawablePadding="5dp"
android:ems="10"
android:hint="#string/e_mail"
android:inputType="text"
android:textSize="25sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/imageView" />
<EditText
android:id="#+id/etP"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="24dp"
android:layout_marginEnd="16dp"
android:background="#color/translucent"
android:drawableStart="#drawable/ic_vector"
android:drawablePadding="5dp"
android:ems="10"
android:hint="#string/password"
android:inputType="textPassword"
android:textSize="25sp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.0"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="#+id/etE" />
<TextView
android:id="#+id/tvFgRegistration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="180dp"
android:layout_marginEnd="76dp"
android:layout_marginBottom="100dp"
android:text="#string/new_u"
android:textColor="#color/white"
android:textSize="18sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" />
</androidx.constraintlayout.widget.ConstraintLayout>
I only want to show a snack bar with a message when XFragment creates.
Can anyone tell me how to solve this and explain me in a few words why?
I found few ways to show a snack bar from a fragment
One of the solution is to use requireView().
Snackbar.make(
requireView(),
"Hello from Snackbar",
Snackbar.LENGTH_SHORT
).show()
This solution will work when you are inside any onClickListner{} you can simply pass it as a view and it will do the job.
binding.button.setOnClickListener {
Snackbar.make(
it,
"Hello from Snackbar",
Snackbar.LENGTH_SHORT
).show()
}
I found a simple solution and seems a Snackbar works excellent only with CoordinatorLayout as root layout so I set CoordinatorLayout as my root layout in the XML file.
In the Snackbar I just put binding.coordinatorlayout where coordinatorlayout is just an id of CoordinatorLayout in the XML file.
Code solution for a fragment is here:
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?
): View? {
_binding = FragmentXBinding.inflate(inflater, container, false)
binding.tvFgRegistration.setOnClickListener {
Navigation.findNavController(binding.root)
.navigate(R.id.action_f1_to_f2)
}
val snackbar: Snackbar = Snackbar.make(binding.coordinatorlayout, "Succesful", Snackbar.LENGTH_LONG)
snackbar.show()
return binding.root
}
XML layout file:
<?xml version="1.0" encoding="utf-8"?>
<androidx.coordinatorlayout.widget.CoordinatorLayout
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/coordinatorlayout" //ID OF COORDINATOR LAYOUT
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic"
tools:context=".XFragment" >
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/ic_backg">
<EditText
android:id="#+id/etE"
android:layout_width="0dp"
.
.
.
</androidx.constraintlayout.widget.ConstraintLayout>
</androidx.coordinatorlayout.widget.CoordinatorLayout>
I faced the same issue while using navigation architecture.
What worked for me was
if(isAdded){
Snackbar.make(requireActivity.window.decorView.rootView,"message").show()
}

Exoplayer with Viewpager2 and recycler view adapter

I have recently discovered abut Viewpager 2 and exoplayer and not sure how to integrate them both. Viewpager contains a list with video player and each takes up the full screen. You can swipe to move to the next video. Can anybody help me with a simple implementation of Exoplayer with Viewpager2
Yes I can help you.
It is a very simple implementation of viewpager2 with ExoPlayer.
It will show you online videos and you can swipe these videos horizontally.
Lets discuss it step by step:
Step 1:
Add internet permission in your Manifest file:
<uses-permission android:name="android.permission.INTERNET"/>
Step 2:
Add ExoPlayer dependency to your build.gradle
// exo player
implementation 'com.google.android.exoplayer:exoplayer:2.17.1'
Step 3 :
Add the following code to your themes.xml
<style name="ClickableView">
<item name="colorControlHighlight">#android:color/darker_gray</item>
<item name="android:background">?selectableItemBackgroundBorderless</item>
</style>
Step 4:
Create a controller layout file to control ExoPlayer named as custom_controller.xml. And then paste bellow code in that file.
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:background="#80000000"
android:layout_height="match_parent">
<ImageView
android:id="#+id/exo_lock"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:padding="10dp"
android:src="#drawable/ic_baseline_lock_open"
android:theme="#style/ClickableView" />
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/sec_controlvid1"
android:orientation="horizontal"
android:layout_centerInParent="true">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_rew"
android:src="#drawable/ic_baseline_replay"
android:layout_marginLeft="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_play"
android:src="#drawable/ic_baseline_play_arrow"
android:layout_marginHorizontal="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_pause"
android:src="#drawable/ic_baseline_pause"
android:layout_marginHorizontal="30dp"
android:theme="#style/ClickableView"/>
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_ffwd"
android:layout_marginRight="30dp"
android:src="#drawable/ic_baseline_forward"
android:theme="#style/ClickableView"/>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/sec_controlvid2"
android:orientation="vertical"
android:padding="8dp"
android:gravity="center"
android:layout_alignParentBottom="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:padding="8dp"
android:gravity="center"
android:layout_alignParentBottom="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_position"
android:textColor="#color/white"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="/"
android:layout_marginHorizontal="4dp"
android:textColor="#CBCDC8"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/exo_duration"
android:layout_weight="1"
android:textColor="#CBCDC8"/>
<ImageView
android:layout_width="30dp"
android:layout_height="30dp"
android:src="#drawable/ic_baseline_fullscreen"
android:id="#+id/bt_fullscreen"
android:theme="#style/ClickableView"/>
</LinearLayout>
<com.google.android.exoplayer2.ui.DefaultTimeBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="#+id/exo_progress"
app:unplayed_color="#42454E"
app:buffered_color="#95989F"
app:played_color="#FF0000"
app:scrubber_color="#FF0000"
android:layout_alignParentBottom="true"
android:layout_marginTop="-8dp"/>
</LinearLayout>
</RelativeLayout>
Step 5:
Create a layout file for representing items in viewpager named as video_card_item.xml and write the following code in it:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:gravity="center_vertical"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.google.android.exoplayer2.ui.PlayerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:id="#+id/statusSliderVideo"
app:use_controller="true"
android:background="#android:color/background_dark"
app:player_layout_id="#layout/exo_player_view"
app:controller_layout_id="#layout/custom_controller"/>
<ImageView
android:id="#+id/statusSliderThumbnailImage"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_centerInParent="true"
android:padding="10dp"
android:scaleType="fitCenter"
android:src="#drawable/ic_default_image" />
<ImageView
android:id="#+id/playPauseBtn"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_centerInParent="true"
android:src="#drawable/ic_play"
app:tint="#color/white" />
<ProgressBar
android:layout_width="80dp"
android:layout_height="80dp"
android:visibility="gone"
android:id="#+id/progress_bar"
android:layout_centerInParent="true"/>
</RelativeLayout>
Step 6 :
Create adapter class for viewpager items named as VideoSliderAdapter.java and write bellow code in it:
package com.example.practiceproject;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo;
import android.media.ThumbnailUtils;
import android.net.Uri;
import android.provider.MediaStore;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ProgressBar;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.RecyclerView;
import com.google.android.exoplayer2.MediaItem;
import com.google.android.exoplayer2.Player;
import com.google.android.exoplayer2.SimpleExoPlayer;
import com.google.android.exoplayer2.ui.PlayerView;
import java.util.ArrayList;
public class VideoSliderAdapter extends RecyclerView.Adapter<VideoSliderAdapter.ViewHolder> {
private Context context;
private ArrayList<String> pathsList;
private AppCompatActivity activity;
private boolean isFullScreen = false;
public static boolean isFullLock = false;
public VideoSliderAdapter(Context context, ArrayList<String> pathsList, AppCompatActivity activity) {
this.context = context;
this.pathsList = pathsList;
this.activity = activity;
}
#NonNull
#Override
public ViewHolder onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
View view = LayoutInflater.from(parent.getContext())
.inflate(R.layout.video_card_item, parent, false);
return new ViewHolder(view);
}
#SuppressLint("ClickableViewAccessibility")
#Override
public void onBindViewHolder(#NonNull ViewHolder holder, int position) {
holder.thumbnailImage.setImageBitmap(ThumbnailUtils.createVideoThumbnail(pathsList.get(position),
MediaStore.Video.Thumbnails.FULL_SCREEN_KIND));
// get data
Uri videoUri = Uri.parse(pathsList.get(position));
holder.bt_fullscreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (!isFullScreen) {
holder.bt_fullscreen.setImageDrawable(
ContextCompat.getDrawable(context, R.drawable.ic_baseline_fullscreen_exit)
);
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_SENSOR_LANDSCAPE);
} else {
holder.bt_fullscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_fullscreen));
activity.setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
}
isFullScreen = !isFullScreen;
}
});
holder.bt_lockscreen.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
if (isFullLock) {
holder.bt_lockscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_lock_open));
} else {
holder.bt_lockscreen.setImageDrawable(ContextCompat.getDrawable(context, R.drawable.ic_baseline_lock));
}
isFullLock = !isFullLock;
lockScreen(isFullLock, holder.sec_mid, holder.sec_bottom);
}
});
holder.playPauseBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
holder.playPauseBtn.setVisibility(View.GONE);
// holder.thumbnailImage.setVisibility(View.GONE);
holder.playerView.setVisibility(View.VISIBLE);
holder.simpleExoPlayer = new SimpleExoPlayer.Builder(context)
.setSeekBackIncrementMs(5000)
.setSeekForwardIncrementMs(5000)
.build();
holder.playerView.setPlayer(holder.simpleExoPlayer);
holder.playerView.setKeepScreenOn(true);
holder.simpleExoPlayer.addListener(new Player.Listener() {
#Override
public void onPlayerStateChanged(boolean playWhenReady, int playbackState) {
if (playbackState == Player.STATE_BUFFERING) {
holder.progressBar.setVisibility(View.VISIBLE);
} else if (playbackState == Player.STATE_READY) {
holder.progressBar.setVisibility(View.GONE);
}
}
});
MediaItem mediaItem = MediaItem.fromUri(videoUri);
holder.simpleExoPlayer.setMediaItem(mediaItem);
holder.simpleExoPlayer.prepare();
holder.simpleExoPlayer.play();
}
});
}
private void lockScreen(boolean isFullLock, LinearLayout sec_mid, LinearLayout sec_bottom) {
if (isFullLock) {
sec_mid.setVisibility(View.INVISIBLE);
sec_bottom.setVisibility(View.INVISIBLE);
} else {
sec_mid.setVisibility(View.VISIBLE);
sec_bottom.setVisibility(View.VISIBLE);
}
}
#Override
public int getItemCount() {
return pathsList.size();
}
public static class ViewHolder extends RecyclerView.ViewHolder {
PlayerView playerView;
ImageView thumbnailImage;
ImageView playPauseBtn;
ImageView bt_fullscreen, bt_lockscreen;
SimpleExoPlayer simpleExoPlayer;
ProgressBar progressBar;
LinearLayout sec_mid, sec_bottom;
public ViewHolder(#NonNull View view) {
super(view);
playerView = view.findViewById(R.id.statusSliderVideo);
thumbnailImage = view.findViewById(R.id.statusSliderThumbnailImage);
playPauseBtn = view.findViewById(R.id.playPauseBtn);
progressBar = view.findViewById(R.id.progress_bar);
bt_fullscreen = view.findViewById(R.id.bt_fullscreen);
bt_lockscreen = view.findViewById(R.id.exo_lock);
sec_mid = view.findViewById(R.id.sec_controlvid1);
sec_bottom = view.findViewById(R.id.sec_controlvid2);
}
}
}
Step 7 :
Paste following code in your activity_main.xml:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:orientation="vertical"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.viewpager2.widget.ViewPager2
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:clipToPadding="true"
android:foregroundGravity="center"
android:overScrollMode="never"
android:id="#+id/videoViewPager"/>
</LinearLayout>
Step 8 :
Paste bellow code in your MainActivity.java:
package com.example.practiceproject;
import androidx.appcompat.app.AppCompatActivity;
import androidx.viewpager2.widget.ViewPager2;
import android.os.Bundle;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
private ViewPager2 viewPager;
private VideoSliderAdapter myAdapter;
ArrayList<String> videoPaths;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
viewPager = findViewById(R.id.videoViewPager);
videoPaths = new ArrayList<>();
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ElephantsDream.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerBlazes.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerEscapes.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerFun.mp4");
videoPaths.add("http://commondatastorage.googleapis.com/gtv-videos-bucket/sample/ForBiggerJoyrides.mp4");
// add paths for video simllarly
myAdapter = new VideoSliderAdapter(getApplicationContext(), videoPaths,
MainActivity.this);
viewPager.setAdapter(myAdapter);
viewPager.setPadding(10, 0, 10, 0);
}
}
Completed
Now you are good to go. Enjoy the app.. Best of Luck.
If you want to get project files (Source Code) for more simplicity, you can get source code from my github profile.
link : https://github.com/AbdullahProgrammer426351/Custom-Video-Slider-with-Exo-Player-and-ViewPager2

How to handle multiple items in RecyclerView

I have four radio button inside the radio group in recyclerview. when i click first position of radio button it reflect on eighth position of radio button. How can i resolve this? If no radio button clicked the group will disable. how can i do this also? when i click the submit button calculate how many radio button clicked?
Xml :
<android.support.v7.widget.CardView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="#+id/txt_question"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:maxLines="5"
android:text="#string/question_1"
android:textColor="#000"
android:textSize="16sp"
android:textStyle="bold" />
<RadioGroup
android:id="#+id/radio_group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="15dp">
<RadioButton
android:id="#+id/radio_option_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
<RadioButton
android:id="#+id/radio_option_4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:maxLines="3" />
</RadioGroup>
</LinearLayout>
</android.support.v7.widget.CardView>
Adapter :
public class TestAdapter extends RecyclerView.Adapter<TestAdapter.RecyclerVH> {
private Context mCtx;
private List<TestResult> testList;
public TestAdapter(Context mCtx, List<TestResult> testList) {
this.mCtx = mCtx;
this.testList = testList;
}
#NonNull
#Override
public RecyclerVH onCreateViewHolder(#NonNull ViewGroup parent, int viewType) {
LayoutInflater layoutInflater = LayoutInflater.from(mCtx);
View view = layoutInflater.inflate(R.layout.list_test, parent, false);
return new RecyclerVH(view);
}
#Override
public void onBindViewHolder(#NonNull final RecyclerVH holder, final int position) {
TestResult test = testList.get(position);
String question = position + 1 + " " + test.getQuestion();
holder.question.setText(question);
holder.option_1.setText(test.getChoice0());
holder.option_2.setText(test.getChoice1());
holder.option_3.setText(test.getChoice2());
holder.option_4.setText(test.getChoice3());
// Log.d("Test",position+"");
}
#Override
public int getItemCount() {
return testList.size();
}
public void setList(ArrayList<TestResult> list) {
this.testList = list;
}
class RecyclerVH extends RecyclerView.ViewHolder {
TextView question;
RadioButton option_1;
RadioButton option_2;
RadioButton option_3;
RadioButton option_4;
RadioGroup group;
RecyclerVH(#NonNull View itemView) {
super(itemView);
question = itemView.findViewById(R.id.txt_question);
option_1 = itemView.findViewById(R.id.radio_option_1);
option_2 = itemView.findViewById(R.id.radio_option_2);
option_3 = itemView.findViewById(R.id.radio_option_3);
option_4 = itemView.findViewById(R.id.radio_option_4);
group = itemView.findViewById(R.id.radio_group);
}
}
}
add this in your adapter, it will handle item according to respective position.
#Override
public int getItemViewType(int position) {
return position;
}

Kotlin - Add action button to ActionBar

I am new to kotlin and I need to add action button to Action bar. I created in folder res/menu this menuTest.xml:
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:android="http://schemas.android.com/apk/res/android">
<item
android:id="#+id/action_fav"
android:icon="#drawable/ic_action_edit"
app:showAsAction="ifRoom"
android:title="#string/edit" />
</menu>
Here is my layout.xml:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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="DetailItem">
<ImageView
android:id="#+id/itemIdImage"
android:layout_width="358dp"
android:layout_height="214dp"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:padding="10dp"
app:srcCompat="#drawable/logo"
tools:layout_editor_absoluteX="13dp"
tools:layout_editor_absoluteY="16dp" />
</RelativeLayout>
And my Activity.kt
class DetailCar : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity)
}
}}
You need to override onCreateOptionsMenu function in your Activity like this:
override fun onCreateOptionsMenu(menu: Menu): Boolean {
menuInflater.inflate(R.menu.menuTest, menu)
return true
}
To handle click events on menu items you need to override onOptionsItemSelected:
override fun onOptionsItemSelected(item: MenuItem): Boolean = when (item.itemId) {
R.id.action_fav -> {
// do stuff
true
}
else -> super.onOptionsItemSelected(item)
}