RecyclerView findViewHolderForAdapterPosition returns sometimes null - android

What I'm trying to do is make a video full screen from RecyclerView and while the video is playing, on pressing the minimize button to put it back into the list. Note that the state of the video is still on play after I minimize it.
Sometimes I get null object from position using .findViewHolderForAdapterPosition
My code:
LinearLayout mAdapterRow = null;
mAdapterRow = (LinearLayout) ((ViewHolder_Article_Video) mList.findViewHolderForAdapterPosition(mVideoPosition)).itemView;
if (mAdapterRow instanceof ViewGroup) {
ViewGroup v = (ViewGroup) nVideoFullScreenLayout.getChildAt(0);
if (v.getParent() != null )
((ViewGroup)v.getParent()).removeView(v); // <- fix
((ViewGroup) mAdapterRow).addView(v);
((ImageView) v.findViewById(R.id.mFullScreen)).setVisibility(View.VISIBLE);
((ImageView) v.findViewById(R.id.mExitFullScreen)).setVisibility(View.GONE);
nVideoFullScreenLayout.removeAllViews();
nVideoFullScreenLayout.setVisibility(View.GONE);
if (nVideoFullScreenLayout.getParent() != null)
((ViewGroup) nVideoFullScreenLayout.getParent()).removeView(nVideoFullScreenLayout);
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(uiOptions);
mHeader.setVisibility(View.VISIBLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mVideoFullScreen = false;
} else {
Log.d("dasdasdas","remove nu: "+ mAdapterRow.getTag());
}
Previously.
When I make the full screen video layout, I'm taking the layout with the video instance from inside the list(RecyclerView) and put it in a new dynamic LinearLayout with the MATCH_PARENT params and set SCREEN_ORIENTATION_LANDSCAPE.
Now the idea was to take the layout with the video instance (full screen) that is over the RecyclerView and put it back into his position.
For some reason findViewHolderForAdapterPosition doesn't always return the layout at the position of where I got the video in the first place.
Also I can see the item at position in list data adapter is not null.
Any idea is appreciated. Thanks in advance.

Finally found a solution that works for me. (this helped https://www.creospiders.com/2016/04/how-to-access-each-view-of-item-by.html , better than a post delay)
Setted the full screen layout on GONE at the beginning of the method so I can have no other view over the reycler, used getViewTreeObserver().addOnGlobalLayoutListener on recycler list to wait for the views to build and setted a boolean value that allows or not to cycle my view in onBindViewHolder (in case the video layout is at limit of being out of screen)
nVideoFullScreenLayout.setVisibility(View.GONE);
View decorView = getWindow().getDecorView();
// Hide the status bar.
int uiOptions = View.SYSTEM_UI_FLAG_LAYOUT_STABLE;
decorView.setSystemUiVisibility(uiOptions);
mHeader.setVisibility(View.VISIBLE);
setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT);
mVideoFullScreen = false;
mAdapter.setCyclingVideoItem(false);
final LinearLayout[] mAdapterRow = {null};
mList.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
mList.getViewTreeObserver().removeOnGlobalLayoutListener(this);
mAdapterRow[0] = (LinearLayout) ((ViewHolder_Article_Video) mList.findViewHolderForAdapterPosition(mVideoPosition)).itemView;
setAndCleanLayouts(mAdapterRow[0]);
mAdapter.setCyclingVideoItem(true);
}
});

Related

findViewById(android.R.id.statusBarBackground) returns null

I'm trying to get StatusBarView (I need it for activity shared element transition animation).
I use the following code in my activity:
View decorView = getWindow().getDecorView();
View statusBar = decorView.findViewById(android.R.id.statusBarBackground);
But statusBar is always null.
I tried this code after onCreate() and after onResume() - no effect.
What's wrong?
Snippet for those who just need a clean answer without reading the whole topic linked by T.Vert
final View decor = getWindow().getDecorView();
decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
decor.getViewTreeObserver().removeOnPreDrawListener(this);
View statusBar = decor.findViewById(android.R.id.statusBarBackground);
return true;
}
});

Switching to binocular mode in Google VR for Android?

I'm developing a VR App using Google VR for Android.
When I switch to Binocular mode (clicking the headset button), appears the following screen:
How can I avoid this screen?
It is possible switch to binocular mode programmatically?
Thanks,
Christian
Yesterday I was working to achieve the same result as you are seeking now. So, I made a workaround for this, I don't know whether its perfect or not but its working at my end.
All you need to do is to get all the child views of the VrVideoView, so that you can customize accordingly.
VrVideoView videoWidgetView = (VrVideoView) findViewById(R.id.video_view);
View framelayout = ((ViewGroup) videoWidgetView).getChildAt(0);
ArrayList<View> list = getAllChildren(framelayout);
for(final View view : list) {
if(view.getId() == R.id.transition_frame){
//set visiblity gone for that cardboard information screen
view.setVisibility(View.GONE);
}
else if(view.getId() == R.id.transition_icon){
//perform click action of the same screen's icon which can
//redirect you to cardboard vr screen directly(binocular mode)
view.performClick();
}
}
Recursive method to get all the child views :
private ArrayList<View> getAllChildren(View v) {
if (!(v instanceof ViewGroup)) {
ArrayList<View> viewArrayList = new ArrayList<View>();
viewArrayList.add(v);
return viewArrayList;
}
ArrayList<View> result = new ArrayList<View>();
ViewGroup viewGroup = (ViewGroup) v;
for (int i = 0; i < viewGroup.getChildCount(); i++) {
View child = viewGroup.getChildAt(i);
ArrayList<View> viewArrayList = new ArrayList<View>();
viewArrayList.add(v);
viewArrayList.addAll(getAllChildren(child));
result.addAll(viewArrayList);
}
return result;
}
I hope this might solve your problem. Additionally you can direct jump in to fullscreen mode as well by calling respective views.
You can try setTransitionViewEnabled(boolean enabled): https://developers.google.com/vr/android/reference/com/google/vr/sdk/base/GvrView.html#setTransitionViewEnabled(boolean)
For switching between mono and vr mode, setVRModeEnabled(boolean enabled): https://developers.google.com/vr/android/reference/com/google/vr/sdk/base/GvrView.html#setVRModeEnabled(boolean)

How to make a set of views invisible in android

I'm trying to make a set of views (that include several textviews and buttons - all in different parent layouts, but in the same activity) invisible if a particular condition is evaluated to false.
The conventional way to do that would be:
findViewById(R.id.myview).setVisibility(View.INVISIBLE);
My question is, will I have to do this for all the views one by one that I want to be invisible, And then toggle them back when I want them visible?
Or, is there a way to avoid the code-repetition?
If the Views are in different parents , you can't do it directly, but you can implement a method to change the visibility of a bunch of Views if you want to keep your code clean:
List<View> relatedViews = new ArrayList<>();
// ...
relatedViews.add(view1);
relatedViews.add(view2);
relatedViews.add(view3);
// ...
changeVisibility(relatedViews, View.INVISIBLE);
// ...
private void changeVisibility(List<View> views, int visibility) {
for (View view : views) {
view.setVisibility(visibility);
}
}
As a side note, you may want to change the visibility to View.GONE instead of View.INVISIBLE so it doesn't take any space in the layout.
you can use something like this. It's not the most elegant solution but works.
The idea is give to each view that you want to hide a same content description, because in the same layout you can not use same id for multiple view. With the same content description you can find all views in your layout and hide them.
That's an example considering the first layout as Linear. You can change obviously ;)
public class TestActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_test);
LinearLayout rootLayout = (LinearLayout)findViewById(R.id.rootLayout);
int childcount = rootLayout.getChildCount();
for (int i=0; i < childcount; i++){
View v = rootLayout.getChildAt(i);
if(v.getContentDescription() != null && v.getContentDescription().equals("invisibleView")){
v.setVisibility(View.INVISIBLE);
//I suggest you to use GONE instead of INVISIBLE to remove the space of the view
}
}
}
}
in your xml give to the object that you want to hide this property
android:contentDescription="invisibleView"
Use varargs method for show or hide multiple views.
for example if you have views like view1, view2.....etc
then just call setVisibility(View.VISIBLE,view1,view2)
public static void setVisibility(int visibility, View... views){
for (View view : views){
view.setVisibility(visibility);
}
}

Android View width and height have not changed after rotation

I have an activity whose layout I need to change after a rotation and part of the layout is a graph that is drawn using the width and height of the view that it will be placed into. The first time my code runs, the graph is drawn correctly, however after the rotation the width and height of the container view are not correct, in fact they appear to be the view as if it was not rotated.
Here is what I have so far,
In my manifest for the activity I am working:
android:configChanges="keyboardHidden|orientation|screenSize"
In my activity I have these following methods:
onCreate
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Bundle extras = getIntent().getExtras();
patient_id = extras.getInt("patient_id");
patient_name = extras.getString("patient_name");
historyDurationType = 12;
constructLayout();
}
constructLayout
public void constructLayout(){
if(landScape){
setContentView(R.layout.activity_bg_history_static_land);
//Set buttons
btnTwelve = (Button)findViewById(R.id.btnTwelveHoursLand);
btnTwentyFour = (Button)findViewById(R.id.btnTwentyFourHoursLand);
btnSeven= (Button)findViewById(R.id.btnSevenDaysLand);
btnTwelve.setOnClickListener(this);
btnTwentyFour.setOnClickListener(this);
btnSeven.setOnClickListener(this);
btnTwelve.setBackgroundColor(getResources().getColor(R.color.light_blue_regular));
btnTwentyFour.setBackgroundResource(android.R.drawable.btn_default);
btnSeven.setBackgroundResource(android.R.drawable.btn_default);
}else{
setContentView(R.layout.activity_bg_history_static);
//Set buttons
btnTwelve = (Button)findViewById(R.id.btnTwelveHours);
btnTwentyFour = (Button)findViewById(R.id.btnTwentyFourHours);
btnSeven= (Button)findViewById(R.id.btnSevenDays);
btnTwelve.setOnClickListener(this);
btnTwentyFour.setOnClickListener(this);
btnSeven.setOnClickListener(this);
btnTwelve.setBackgroundColor(getResources().getColor(R.color.light_blue_regular));
btnTwentyFour.setBackgroundResource(android.R.drawable.btn_default);
btnSeven.setBackgroundResource(android.R.drawable.btn_default);
btnComment = (Button)findViewById(R.id.btnCommentGraph);
btnComment.setOnClickListener(this);
populateOtherContent(officialReadings12);
TextView tvStats = (TextView)findViewById(R.id.txtStatistics);
Typeface chunkFiveFont = Typeface.createFromAsset(getAssets(), "fonts/chunkfivettfversion.ttf");
tvStats.setTypeface(chunkFiveFont);
TextView tvReading = (TextView)findViewById(R.id.txtReadingTitle);
tvReading.setTypeface(chunkFiveFont);
comment = null;
}
if(needData){
getLatestReadings();
}
populateGraph();
}
populateGraph
public void populateGraph(){
if(landScape){
graph_container = (LinearLayout)findViewById(R.id.graph_land_content_layout);
}else{
graph_container = (LinearLayout)findViewById(R.id.graph_content_layout);
}
//Create graphlayout
mainGraph_Layout = new RelativeLayout(this);
RelativeLayout.LayoutParams glParams = new RelativeLayout.LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT);
mainGraph_Layout.setId(909);
mainGraph_Layout.setLayoutParams(glParams);
graph_container.addView(mainGraph_Layout);
graph_container.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
if(needsGraph){
layoutGraph();
needsGraph = false;
}
}
});
}
layoutGraph
public void layoutGraph(){
viewWidth = mainGraph_Layout.getWidth();
viewHeight = mainGraph_Layout.getHeight();
//MORE STUFF IS HERE BUT NOT IMPORTANT
}
onConfigurationChanged
#Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
ActionBar actionBar = getActionBar();
if(newConfig.orientation==Configuration.ORIENTATION_LANDSCAPE){
//Config is landscape here
actionBar.hide();
needData = false;
landScape = true;
needsGraph = true;
constructLayout();
}else{
//Config is portrait here
actionBar.show();
needData = false;
landScape = false;
needsGraph = true;
constructLayout();
}
}
After rotation, it is at the layoutGraph() viewWidth and viewHeight objects where I have the problem. I had assumed by that point (having used the global layout listener) that the values would be correct. My understanding was that the listener would only have been triggered once "graph_container" was completed (and landscape or portrait) and so when calling layoutGraph() the width and height of "mainGraph_layout" (a child a graph_container, widths and heights set to MATCH_PARENT) would be good to go. It appears that the width and height I am getting are as if the phone is still portrait, and worth noting it appears that the removal of the action bar has also been taken into account.
Sorry for the long question but I thought it best to show all the code. If anything else needs to be shown then please let me know.
Thanks in advance,
Josh
There is a much better way to do this.
Use resource folders
Put your default layout files in res/layout, and the ones for landscape in res/layout-land. In other words, move res/layout/activity_bg_history_static_land.xml to res/layout-land/activity_bg_history_static.xml.
In onCreate, call
setContentView(R.layout.activity_bg_history_static);
The system will pick the file from res/layout-land when you are in landscape orientation, res/layout otherwise.
If you have views that are only present in one layout but not the other e.g. the comment button, wrap the code inside a null check like this:
btnComment = (Button) findViewById(R.id.btnCommentGraph);
if (btnComment != null) {
btnComment.setOnClickListener(this);
}
For populateGraph(), make sure both res/layout/activity_bg_history_static.xml and res/layout-land/activity_bg_history_static.xml has android:id="#+id/R.id.graph_content. Then you can do findViewById(R.id.graph_content) and get the LinearLayout you need.
Save data across rotation
In your activity, override onSaveInstanceState(), and save the data from getLatestReadings() into the bundle.
Then, in onCreate:
if (savedInstanceState == null) {
getLatestReadings();
} else {
// Restore latest readings from savedInstanceState
}
With that, you can let the system handle the rotation i.e. remove this from your manifest:
android:configChanges="keyboardHidden|orientation|screenSize"
Since the system is handling the rotation, you don't need to have a view tree observer any more. And you don't have to override onConfigurationChanged.

Resize elements in bar chart by multiplying with a factor

I am trying to create a bar chart in android where each bar consists of one Viewand one TextView.
I add these cells to a HorizontalScrollView. This works fine, all my bars appear.
Now I want to resize these bars(as they now all appear in full height) by multiplying them with a factor.
This is the activity class that i Use.
private ViewGroup linearScrollLayout;
private HorizontalScrollView hScrollView;
private ArrayList<NutrientCell> nutrientsData;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.box_plot);
this.hScrollView = (HorizontalScrollView) findViewById(R.id.horizontalScrollView1);
this.linearScrollLayout = (ViewGroup) this.hScrollView
.findViewById(R.id.linearScrollLayout);
try {
Intent intent = getIntent();
this.nutrientsData = (ArrayList<NutrientCell>) intent
.getSerializableExtra("nutrientsData");
//
} catch (Exception e) {
// TODO: handle exception
}
this.initChart();
}
private void initChart() {
for (NutrientCell c : this.nutrientsData) {
RelativeLayout rlt = (RelativeLayout) getLayoutInflater().inflate(
R.layout.hv_boxplot_cell, this.linearScrollLayout, false);
((TextView) rlt.findViewById(R.id.textView1)).setText(c
.getNutrientName().toString());
View v = ((View) rlt.findViewById(R.id.vv1));
v.setBackgroundColor(c.getColor());
this.linearScrollLayout.addView(rlt);
}
}
Now, in the loop found in initChart() I iterate over all elements in an ArrayList, each of which has a percentage variable. This is the variable I would like to multiply the height with.
I have tried to just multiply the height of the LayoutParams of the inflated RelativeLayout found in initChart but as this is called in onCreate(), its height property is not correct.
So how can I make sure that the inflated RelativeLayout I add to my View has a height corresponding to the percentage obtained from c(c.getPercentage())
What exactly is the percentage used for? If the percentage is used to scale the view based on it's initial size, you could probably use the view's setScaleY() method to change it's height.

Categories

Resources