Espresso select children of included layout - android

I have been using Espresso to carry out automated UI testing with an Android app. (I have been trying to find a resolution to the issue whilst at home from work, so I don’t have the exact examples and errors, but I can update tomorrow morning). I have run into an issue with unit testing buttons within a layout that is included multiple times within a single user interface. Below is a quick example:
<include
android:id="#+id/include_one"
android:layout="#layout/boxes" />
<include
android:id="#+id/include_two"
android:layout="#layout/boxes" />
<include
android:id="#+id/include_three"
android:layout="#layout/boxes" />
Here is an example of what is within the #layout/boxes:
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:id="#+id/button1" />
<Button
android:id="#+id/button2" />
</RelativeLayout>
I am seemingly unable to access button one within the include I want “include_one”, without accessing all three of the buttons.
I have tried accessing the buttons with the following:
onView(allOf(withId(R.id.include_one), isDescendantOfA(withId(R.id.button1)))).perform(click());
and
onView(allOf(withId(R.id.button1), hasParent(withId(R.id.include_one)))).perform(click());
Both of which I found from this answer: onChildView and hasSiblings with Espresso Unfortunately I haven’t had any success!
I know this isn’t great, but as I am not with my work computer I can’t tell you the exact errors I have come across, but I have encountered:
com.google.android.apps.common.testing.ui.espresso.AmbiguousViewMatcherException
also an error telling me there were no matches found.
The code I am using makes sense, although I am new to using Espresso Can anyone offer some advice, or point out what I may be misunderstanding?

This is a common pitfall when trying to <include/> the same custom xml several times in the same layout.
If you now try calling
Button button1 = (Button) findViewById(R.id.button1);
since the boxes.xml is included more than once, you will always get as a result the button present in the first sub layout, and never another one.
You were pretty close but you need to use the withParent() view matcher.
onView(allOf(withId(R.id.button1), withParent(withId(R.id.include_one))))
.check(matches(isDisplayed()))
.perform(click());

I had similar issue, applied accepted answer but didn't work. Hereby I come across look into expected level of parent hierarchy
private static final class WithParentMatcher extends TypeSafeMatcher<View> {
private final Matcher<View> parentMatcher;
private int hierarchyLevel;
private WithParentMatcher(Matcher<View> parentMatcher, int hierarchyLevel) {
this.parentMatcher = parentMatcher;
this.hierarchyLevel = hierarchyLevel;
}
#Override
public void describeTo(Description description) {
description.appendText("has parent matching: ");
parentMatcher.describeTo(description);
}
#Override
public boolean matchesSafely(View view) {
ViewParent viewParent = view.getParent();
for (int index = 1; index < hierarchyLevel; index++) {
viewParent = viewParent.getParent();
}
return parentMatcher.matches(viewParent);
}
}
Then create a helper method
public static Matcher<View> withParent(final Matcher<View> parentMatcher, int hierarchyLevel) {
return new WithParentMatcher(parentMatcher, hierarchyLevel);
}
Here is the usage
onView(allOf(withId(R.id.button1), withParent(withId(R.id.include_one), 2))).perform(click());

Related

Two way data binding with two EditText views

I'm having trouble making two Edit Text views that update when one is changed. To provide some context, see the following image:
Also the view in action (can't have it embedded apparently.):
https://i.imgur.com/an6Kodx.mp4
Here, we add targets (T1, T2, T3 etc.), then draw an arc and user may set start and finish points of the camera (gray and red icons respectively.) Then, we get the total move value (in degrees). This value will determine amount the motor will rotate (The app is basically a controller for users to have automated photo-shoots).
What I try to achieve is that, when user enters a photo number, right edittext divides total move degrees to that count and show angle per photo and vice-versa.
However, I'm a bit lost among all the online content demonstrating various examples (like password strength etc.)
I've included DataBinding on gradle.
I've created a custom class (RotaryPhotoShoot) to have a model of three main parameters (angle per shoot, number of photos and total move).
I've moved my cosntraint layout to layout root.
I've created data as seen on following code blocks.
RotaryPhotoShoow.java (my model)
package com.example.macrorecapp.models;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
public class RotaryPhotoShoot extends BaseObservable {
private static final String TAG = "Rotary Photo Shoot";
private float anglePerPhotos;
private int numberOfPhotos;
private int totalMoveDegrees;
public RotaryPhotoShoot(float anglePerPhotos,int numberOfPhotos, int totalMoveDegrees) {
this.anglePerPhotos = anglePerPhotos;
this.numberOfPhotos = numberOfPhotos;
this.totalMoveDegrees = totalMoveDegrees;
}
#Bindable
public float getAnglePerPhotos() {
return anglePerPhotos;
}
#Bindable
public int getNumberOfPhotos() {
return numberOfPhotos;
}
#Bindable
public int getTotalMoveDegrees() {
return totalMoveDegrees;
}
#Bindable
public void setAnglePerPhotos(float anglePerPhotos) {
this.anglePerPhotos = anglePerPhotos;
}
#Bindable
public void setNumberOfPhotos(int numberOfPhotos) {
this.numberOfPhotos = numberOfPhotos;
}
#Bindable
public void setTotalMoveDegrees(int totalMoveDegrees) {
this.totalMoveDegrees = totalMoveDegrees;
}
}
activity_rotary_photo_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="photoShoot"
type="com.example.macrorecapp.models.RotaryPhotoShoot" />
</data>
<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="#color/appMainBackground"
tools:context=".features.rotary.RotaryPhotoSettings">
...
<com.example.macrorecapp.features.shared.views.RotaryView
android:id="#+id/rotaryPhotoView"
android:layout_width="360dp"
android:layout_height="360dp"
app:isClockwise="true"
app:targetList="#array/targets"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/h_guideline1"
app:layout_constraintBottom_toTopOf="#id/h_guideline2" />
<EditText
android:id="#+id/numberOfPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+photoShoot.numberOfPhotos}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/numberOfPhotosSubtext"
app:layout_constraintEnd_toStartOf="#id/v_guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/numberOfPhotosBG"
android:importantForAutofill="no"
android:inputType="number" />
...
<EditText
android:id="#+id/anglePerPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+photoShoot.anglePerPhotos+(char) 0x00B0}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/anglePerPhotosSubtext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#id/v_guideline"
app:layout_constraintTop_toTopOf="#+id/anglePerPhotosBG"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
...
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
And finally RotaryPhotoSettings.java
package com.example.macrorecapp.features.rotary;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
//import com.example.macrorecapp.features.shared.views.RotaryView;
import com.example.macrorecapp.models.RotaryPhotoShoot;
public class RotaryPhotoSettings extends AppCompatActivity {
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
//RotaryView mPhotoRotaryView;
//private int mTotalMoveInDegrees;
ActivityRotaryPhotoSettingsBinding mBinding;
RotaryPhotoShoot mRotaryPhotoShoot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);
mRotaryPhotoShoot = new RotaryPhotoShoot(6.88f, 25, 178);
mBinding.setPhotoShoot(mRotaryPhotoShoot);
//mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
//mPhotoRotaryView.addTarget(300);
//mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();
}
public void goBack(View view) {
view.startAnimation(buttonClick);
finish();
}
public void openThreeSixtyPhotoRotary(View view) {
}
}
Currently I have no errors whatsoever and I'm sure I'll be able change views one way when I programmatically set them in activity. What I feel like I should do is, first use #={} syntax in xmls to begin with. Then I may need to have custom adapters or binders. I've also seen that people use ObservableInt etc. which I got a bit lost. I needed to set my getTotalMove function to set static to get it from RotaryView.java but from then on I couldn't progress.
I'd like to have some pointers what to do onward. I think I can easily handle rounding up numbers where I implement the custom binder/adapter. I know for example the angle may be decimal while the photo count needs to be integer. I will be rounding up photo count and change the angle itself to closest possible value once it is done being edited. I will also need to determine whether start and end points will be included in the interval. Like, for 100 degrees, with 20 degrees per shoot, it'd be like this:
0: S__S__S__S__S__S :100 Thus 6 photos etc.
Before I implement any listeners etc., I figured I could ask here first, because obviously point of using the Data Binding library is to get rid of bunch of listeners and so on. I would appreciate some sort of example where two EditText views change eachother.
Once I figure out how to set non-edited EditText, I'll be dealing with extra considerations I mentioned above, but first I need to get done with two way binding part. I suppose this "two way" is between view and view model, not directly between views, obviously. So I don't know if I can have a trick like #={``+photoShoot.totalMove/photoShoot.anglePerPhoto} etc. in xml.
Anyways, the post is much longer than it is supposed to be, my apologies.
This looked pretty straight-forward at first glance, but the more I look into it, the more complicated it gets. Maybe I'm just confusing myself.
I'd like to add some partial-answer to my own question. I tried to adjust info that I had from following link in my own use case:
https://www.bignerdranch.com/blog/two-way-data-binding-on-android-observing-your-view-with-xml/
I managed to change angle box (one on the right) with following changes:
I deleted some unnecessary variables in my custom view you see above and added a public "Total Move" getter. I use this in my model class RotaryPhotoShoot.
I also added #={} in my xml as you can see updated code below. This combined with notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos); made it possible to update angle box.
Before adding another wall of text, I'll just add the relevant parts of my code for further reference to other people.
RotaryPhotoSettings.java (The activity class that utilizes binding.)
package com.example.macrorecapp.features.rotary;
import androidx.appcompat.app.AppCompatActivity;
import androidx.databinding.DataBindingUtil;
import android.os.Bundle;
import android.view.View;
import android.view.animation.AlphaAnimation;
import com.example.macrorecapp.R;
import com.example.macrorecapp.databinding.ActivityRotaryPhotoSettingsBinding;
import com.example.macrorecapp.models.RotaryPhotoShoot;
public class RotaryPhotoSettings extends AppCompatActivity {
private AlphaAnimation buttonClick = new AlphaAnimation(1F, 0.2F);
//RotaryView mPhotoRotaryView;
//private int mTotalMoveInDegrees;
ActivityRotaryPhotoSettingsBinding mBinding;
RotaryPhotoShoot mRotaryPhotoShoot;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mBinding = DataBindingUtil.setContentView(this, R.layout.activity_rotary_photo_settings);
mRotaryPhotoShoot = new RotaryPhotoShoot(6.88f, 25);
mBinding.setPhotoShoot(mRotaryPhotoShoot);
//mPhotoRotaryView = findViewById(R.id.rotaryPhotoView);
//mPhotoRotaryView.addTarget(300);
//mTotalMoveInDegrees = mPhotoRotaryView.getTotalMoveInDegrees();
}
public void goBack(View view) {
view.startAnimation(buttonClick);
finish();
}
public void openThreeSixtyPhotoRotary(View view) {
}
}
My model class, RotaryPhotoShoot.java
package com.example.macrorecapp.models;
import androidx.databinding.BaseObservable;
import androidx.databinding.Bindable;
import com.example.macrorecapp.features.shared.views.RotaryView;
public class RotaryPhotoShoot extends BaseObservable {
private static final String TAG = "Rotary Photo Shoot";
private float anglePerPhotos;
private int numberOfPhotos;
public RotaryPhotoShoot(float anglePerPhotos, int numberOfPhotos) {
this.anglePerPhotos = anglePerPhotos;
this.numberOfPhotos = numberOfPhotos;
}
#Bindable
public float getAnglePerPhotos() {
return RotaryView.getTotalMoveInDegrees()/(float) numberOfPhotos;
}
#Bindable
public int getNumberOfPhotos() {
return numberOfPhotos;
}
#Bindable
public void setAnglePerPhotos(float anglePerPhotos) {
this.anglePerPhotos = RotaryView.getTotalMoveInDegrees()/numberOfPhotos;
}
#Bindable
public void setNumberOfPhotos(int numberOfPhotos) {
this.numberOfPhotos = numberOfPhotos;
notifyPropertyChanged(com.example.macrorecapp.BR.numberOfPhotos);
notifyPropertyChanged(com.example.macrorecapp.BR.anglePerPhotos);
}
}
The activity layout file that have views in it, activity_rotary_photo_settings.xml
<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="photoShoot"
type="com.example.macrorecapp.models.RotaryPhotoShoot" />
</data>
<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="#color/appMainBackground"
tools:context=".features.rotary.RotaryPhotoSettings"
android:focusable="true"
android:focusableInTouchMode="true">
<com.example.macrorecapp.features.shared.views.RotaryView
android:id="#+id/rotaryPhotoView"
android:layout_width="360dp"
android:layout_height="360dp"
app:isClockwise="true"
app:targetList="#array/targets"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="#id/h_guideline1"
app:layout_constraintBottom_toTopOf="#id/h_guideline2" />
<EditText
android:id="#+id/numberOfPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#={``+photoShoot.numberOfPhotos}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/numberOfPhotosSubtext"
app:layout_constraintEnd_toStartOf="#id/v_guideline"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="#+id/numberOfPhotosBG"
android:importantForAutofill="no"
android:inputType="number" />
<EditText
android:id="#+id/anglePerPhotosEdittext"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#{``+String.format(`%.2f`, photoShoot.anglePerPhotos)+(char) 0x00B0}"
android:textAlignment="center"
android:ems="4"
android:textSize="15sp"
android:textColor="#FFFFFFFF"
app:layout_constraintBottom_toTopOf="#+id/anglePerPhotosSubtext"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintStart_toEndOf="#id/v_guideline"
app:layout_constraintTop_toTopOf="#+id/anglePerPhotosBG"
android:importantForAutofill="no"
android:inputType="numberDecimal" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
Current problems that I could use some markers:
I need cross changes, currently I don't know how to tell whether a change is coming from the EditText being changed by typing or not. When the change is coming from other box, I will format/round the value properly and update the EditText view.
I could just use a bool value that I would toggle depending on whether the change is coming from manual editing or value changing progromatically. This would help me prevent infinite loop. However, as I said above, I am not sure what to listen to in order to achieve that.
Another behavior I would like to have is that, when camera start-finish icons are moved and TotalMove (in degrees) changed, I want to have numberOfPhotos fixed and update anglePerPhotos only. I may need to add binding in RotaryView.java for that. If this is an overkill, I may just add a trigger/listener on RotaryPhotoShoot. Currently. when I make a change in numberOfPhotos after I change the camera positions, angle is calculated properly as expected.
One little bug(?) I have is that, I cannot delete the last digit in numberOfPhotos field. See the following webm video below:
https://gfycat.com/distortedyoungdairycow
One thing I've realized is that, getter and setters in model class alone achieves what I need to do. This indeed removes the need to mess around with listeners and custom adapters. Since I'm using two EditTexts interchangeably, I may end up using them still.
Note that you can use any built-in Java functions (see string formatting I used in anglePerPhotos field). If necessary, I know how to import a class in <data></data> block.
I'll add one more link before I finish this update-answer for those who may be lost how to set if Data Binding in their project for the first time:
https://www.youtube.com/watch?v=v4XO_y3RErI
This solved my problem:
android:text="#{String.valueOf(product.quantityInventory + product.quantityShop)}"

OnClickListener/OnTouchListener on LinearLayout inside RecyclerView not called first time after a quick swipe (for up to 3 seconds)

I have an XML like this (I simplified from the original one, but it still reproduces the issue):
<?xml version="1.0" encoding="utf-8"?>
<merge xmlns:android="http://schemas.android.com/apk/res/android">
<LinearLayout
android:id="#+id/xContainer"
android:clickable="true" // does not help
android:focusable="true" // does not help
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical"
android:paddingBottom="8dp"
android:paddingTop="8dp">
<TextView
android:duplicateParentState="true" // does not help
android:clickable="false" // does not help
android:id="#+id/xText"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:padding="8dp"
android:text="#string/xText"
android:textSize="14sp" />
</LinearLayout>
</merge>
and it's included from a CardView like this:
<include layout="#layout/other_stuff_first" />
<include layout="#layout/my_clickable_layout" />
Then I display the item dynamically and attach an OnClickListener to it, in the same method:
public class XViewHolder extends RecyclerView.ViewHolder {
private final View xContainer;
...
public XViewHolder(#NonNull View itemView) {
xContainer = itemView.findViewById(R.id.xContainer);
}
...
private void bindStuff(RecyclerView.ViewHolder holder, int position) {
if (something) {
xContainer.setVisibility(View.VISIBLE);
xContainer.setOnClickListener(v -> {
// do some stuff
});
} else {
xContainer.setVisibility(View.GONE);
xContainer.setOnClickListener(null);
}
}
}
public class ParentAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
#Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
...
((XViewHolder) xViewHolder).bindStuff();
}
}
I put some breakpoints, went through the code in the debugger, and it's properly executed (otherwise it would not show up in the UI at all), so the listener is set.
However, the first time when I click the container, most of the time nothing happens. On the consecutive clicks, it works (90% of time on 2nd click and 100% of time on 3rd+ click). I always click in the same way, the container is big, even if I put my whole finger down with a big force, first click doesn't register.
I found several similar questions, but they're either "all or nothing" (whereas in my case it's just sporadic), or due to some other issues. In my app, there's no work on the main thread after the UI is displayed.
Any ideas what can be wrong?
Edit: after some investigation, the issue only happens if:
my_clickable_layout is at the bottom of the scrolling container and not initially visible on screen (only becomes visible after the user scrolls down), AND
the user scrolls down fast, AND
the user taps my_clickable_layout within 0-3 seconds after the scroll.
If the layout is immediately visible, OR user scrolls down slowly, OR user taps more than once, then the taps are dispatched properly.
The RecyclerView itself receives the touch events, because I can always see the logs from the code below, even if I don't see the logs from my children listeners.
recyclerView = view.findViewById(R.id.recycler_view);
recyclerView.addOnItemTouchListener(new RecyclerView.SimpleOnItemTouchListener() {
#Override
public boolean onInterceptTouchEvent(RecyclerView rv, MotionEvent e) {
Timber.w("onInterceptTouchEvent");
return false;
}
});
At this moment I believe this might be a bug in RecyclerView, which wrongly consumes the first event after a fast scroll - perhaps to detect "end of scrolling" tap?

Android: how to use Espresso to test that a buttons bgcolor has changed when it's being held down?

I want to use Espresso to test that a button that has a color selector as it's background is really changing color properly when the user presses on it. However, when I try to do this with espresso the actual click is being registered so fast that the button performs it's behavior (starting a progressbar) and the test fails with "view not found". How can I test that the background color changed when the user presses on it without/before performing the button logic? Essentially what I'm looking for here is a way to simulate OnTouchListener's Action_Down.
Espresso.onView(ViewMatchers.withId(R.id.somebutton)).perform(ViewActions.click());
Espresso.onView(ViewMatchers.withText(R.string.somebuttonText)).check(ViewAssertions.matches(withTextColor(Color.BLACK)));
public static Matcher<View> withTextColor(final int color) {
Checks.checkNotNull(color);
return new BoundedMatcher<View, TextView>(TextView.class) {
#Override
public boolean matchesSafely(TextView warning) {
return color == warning.getCurrentTextColor();
}
#Override
public void describeTo(Description description) {
description.appendText("with text color: ");
}
};
}
The error that I'm getting is:
android.support.test.espresso.NoMatchingViewException: No views in hierarchy found matching: with string from resource id: <someid>
I also tried to do it this way and it fails with the same error:
ViewInteraction somebuttoninteraction = Espresso.onView(ViewMatchers.withText(R.string.somebuttontext));
somebuttoninteraction.perform(ViewActions.click()).check(ViewAssertions.matches(withTextColor(Color.BLACK)));
I also tried like this (longclick instead of click) but still the same:
somebuttoninteraction.perform(ViewActions.longClick()).check(ViewAssertions.matches(withTextColor(Color.BLACK)));
The solution (weirdly enough) was to do something long and convoluted like this:
Espresso.onView(ViewMatchers.withText(R.string.somebuttontext)).inRoot(RootMatchers.withDecorView(CoreMatchers.is(getActivity().getWindow().getDecorView()))).perform(ViewActions.click()).check(ViewAssertions.matches(withTextColor(Color.BLACK)));
in order to search for the view not in the foreground of the window after the click.

Can we embed button inside the min3d screen?

Is it possible to insert a button at the bottom of a working 3d animation done with Min3d framework in android. I do have a working 3d model car which is rotating. I want to put a button at the bottom of this working animation screen. Is it possible since i am not using any layout.Please explain me with an example so that i can replicate the same with my program.
Yes. Rather, the procedure is to rather add the min3d framework to the layout, using glSurfaceView. The following cocde highlights how to achieve the same, assuming you have the other basics (such as loading the object ) covered. If not, links for the same is provided at the end of this brief.
//import statements
public class threedviewActivity extends RendererActivity implements View.OnClickListener,View.OnTouchListener{
//onClick and onTouch in case you want to recognize both touch and click on the button
//initialize the variables you require
#Override
public void onCreateSetContentView() {
setContentView(R.layout.activity_example);
RelativeLayout R1 = (RelativeLayout)this.findViewById(R.id.SceneHolder);
R1.addView(_glSurfaceView); //adding the min3d view into the layout
Button example_1 = (Button)this.findViewById(R.id.example_1);
Button example_2 = (Button)this.findViewById(R.id.example_2);
example_1.setOnTouchListener(this);
example_2.setOnClickListener(this);
}
public boolean onTouch(View $v, MotionEvent event) {
switch($v.getId())
{
case R.id.example_1:
//Your actions and things to do
case R.id.example_2:
//your code
}
}
public void onClick(View $v)
{
//similar to above
}
public void initScene()
{
//initialize object and other activities related to the 3d container
}
#Override
public void updateScene()
{
//update effects such as rotation on the object here, based on the button click or touch, etc.
}
}
And the xml file containing the layout/activity should look something like this :
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent"
>
<Button
//your data
android:id="#+id/example_1"
/>
<Button
//your data
android:id="#+id/example_2"
/>
<RelativeLayout
//nested layout which will hold the 3d container
android:id="#+id/SceneHolder">
</RelativeLayout>
</RelativeLayout>
for understanding more about working in initScene() function, you can refer here and here.
You can also add extra effects, by playing around with the lighting properties, as stated here
The basic example for adding into the layout was taken from here . The same page also provides links to many examples in case you want to work with in future.

How to Switch Views at Runtime?

I have the following code in my accounting application:
// switch View to the Customer layout, widget id's are the same on both layouts
private void hideExpenseView() {
setContentView(R.layout.customer_invoices);
}
// switch View to the Supplier layout
private void hideIncomeView() {
setContentView(R.layout.supplier_invoices);
}
The above does not work, as when you switch the ContentView, you lose all variable mappings. You have to map variables after you setContentView() unfortunately.
If this worked, this would be a beautifully simple solution for my app. See, I've named the widgets in both xml layouts the same ids. Instead of hiding elements of one xml layout based on different states, I switch the entire View to the appropriate layout - whether entering a Customer sales invoice, or a Supplier expense invoice.
By switching Views, I would have basically 6 lines of code taking care of the UI transition, very simple.
I hope this is still possible in another capacity, can someone please push me in the right direction?
Check out ViewSwitcher : see http://developer.android.com/reference/android/widget/ViewSwitcher.html
That, or base your activities layout in a framelayout that includes supplier_invoices.xml and customer_invoices.xml. Then your homegrown hide-n-show will be g2g. Tho, you might need to change the ids still.
You can wrap your views in two LinearLayouts, one for R.layout.customer_invoices and another for R.layout.supplier_invoices.
You need to implement your own findViewById.
private static final int LAYOUT_EXPENSE = 1;
private static final int LAYOUT_INCOME = 2;
private int currentLayout = LAYOUT_EXPENSE;
private LinearLayout expenseContainer, incomeContainer;
// switch View to the Customer layout, widget id's are the same on both layouts
private void hideExpenseView() {
switchLayout(LAYOUT_INCOME);
}
// switch View to the Supplier layout
private void hideIncomeView() {
switchLayout(LAYOUT_EXPENSE);
}
private void switchLayout(int layout) {
currentLayout = layout;
if (layout == LAYOUT_EXPENSE) {
expenseContainer.setVisibility(VISIBLE);
incomeContainer.setVisibility(GONE);
} else {
expenseContainer.setVisibility(GONE);
incomeContainer.setVisibility(VISIBLE);
}
}
public View findViewById(int id) {
if (layout == LAYOUT_EXPENSE) return expenseContainer.findViewById(id);
else return incomeContainer.findViewById(id);
}
I think you got my idea.
Do like this
main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<LinearLayout
android:id="#+id/customer_invoices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- put customer_invoices related tools like TextView, Button, ImageView here -->
</LinearLayout>
<LinearLayout
android:id="#+id/supplier_invoices"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical" >
<!-- put supplier_invoices related tools like TextView, Button, ImageView here -->
</LinearLayout>
</LinearLayout>
Java code:
public class TestActivity extends Activity {
View supplier_invoices,customer_invoices;
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
supplier_invoices = findViewById(R.id.supplier_invoices);
customer_invoices = findViewById(R.id.customer_invoices);
}
// switch View to the Customer layout, widget id's are the same on both layouts
private void hideExpenseView() {
setContentView(R.layout.customer_invoices);
customer_invoices.setVisibility(View.VISIBLE);
supplier_invoices.setVisibility(View.GONE);
}
// switch View to the Supplier layout
private void hideIncomeView() {
supplier_invoices.setVisibility(View.VISIBLE);
customer_invoices.setVisibility(View.GONE);
}
}

Categories

Resources