I need a method to get the information if my View is an instance of Button.
MyButton is a subclass of Button.
public void onCreate(Bundle s)
{
...
MyButton button = new MyButton(activity);
getViewType(button);
}
private <V extends View> V getViewClass(V view)
{
Class<V> clazz = (Class<T>) view.getClass();
if (clazz instanceof Button) {
return Button.class; //the information I need to get
}
}
The instanceof is not working here.
I can just compare clazz with Classes like you can see below. But I need the information if this view instance is a child of the class Button.
if (clazz == Button.class) ... //returns false
if (clazz == MyButton.class) ... //returns true
EDIT:
I got it. Solution:
if (Button.class.isAssignableFrom(clazz))
{
...
}
Why not just do this?
private <V extends View> V getViewClass(V view)
{
if (view instanceof Button) {
return Button.class; //the information I need to get
}
}
Related
There are posts on how to click on a certain item in a RecyclerView at whatever position you input, but is there a way to click on all the views, especially given the fact that I may not know how many views there will be in the Recycler View.
I thought of getting the number of items in the RecyclerView like in this link but it involves getting the actual RecyclerView from the activity which sometimes is not possible.
I've also seen a block of code like:
public static class RecyclerViewItemCountAssertion implements ViewAssertion { private final int expectedCount;
public RecyclerViewItemCountAssertion(int expectedCount) {
this.expectedCount = expectedCount;
}
#Override
public void check(View view, NoMatchingViewException noViewFoundException) {
if (noViewFoundException != null) {
throw noViewFoundException;
}
RecyclerView recyclerView = (RecyclerView) view;
RecyclerView.Adapter adapter = recyclerView.getAdapter();
assertThat(adapter.getItemCount(), is(expectedCount));
}
}
But i'm unsure of how to manipulate to get the count
So simply in your test:
final View viewById = activityTestRule.getActivity().findViewById(R.id.your_recycler_view_id);
final RecyclerView recyclerView = (RecyclerView) viewById;
final RecyclerView.Adapter adapter = recyclerView.getAdapter();
final int itemsCount = adapter.getItemCount();
So you can iterate through from 0 to itemsCount-1
You can use this class to get recycler view element at position (in your case 0 to itemsCount-1)
public class RecyclerViewMatcher {
private final int recyclerViewId;
public RecyclerViewMatcher(int recyclerViewId) {
this.recyclerViewId = recyclerViewId;
}
public Matcher<View> atPosition(final int position) {
return atPositionOnView(position, -1);
}
public Matcher<View> atPositionOnView(final int position, final int targetViewId) {
return new TypeSafeMatcher<View>() {
Resources resources = null;
View childView;
public void describeTo(Description description) {
String idDescription = Integer.toString(recyclerViewId);
if (this.resources != null) {
try {
idDescription = this.resources.getResourceName(recyclerViewId);
} catch (Resources.NotFoundException var4) {
idDescription = String.format("%s (resource name not found)", recyclerViewId);
}
}
description.appendText("with id: " + idDescription);
}
public boolean matchesSafely(View view) {
this.resources = view.getResources();
if (childView == null) {
RecyclerView recyclerView =
(RecyclerView) view.getRootView().findViewById(recyclerViewId);
if (recyclerView != null && recyclerView.getId() == recyclerViewId) {
childView = recyclerView.findViewHolderForAdapterPosition(position).itemView;
} else {
return false;
}
}
if (targetViewId == -1) {
return view == childView;
} else {
View targetView = childView.findViewById(targetViewId);
return view == targetView;
}
}
};
}}
and use this class like this:
onView(new RecyclerViewMatcher(R.id.your_recycler_view_id)
.atPositionOnView(0, R.id.your_item_body))
.perform(click());
So finally you are able to click all items in your recyclerview. I hope it would help. Cheers.
I'm thinking out loud here, but a couple of things I would try are:
a- Check to see if there is any way to put this in the ViewHolder/RecyclerView Adapter. That really depends on when you want to trigger the click on all items so I'm guessing it won't work for you.
b- Try a while loop with a try/catch for getting the item. This doesn't sound like a good idea from a software engineering best practices perspective, but it should work if your goal is just to get something working.
c- If you can't get the recycler view itself, is there some way you can access the arraylist (or whatever) you used to populate the recyclerView itself?
Some questions:
1- In what cases is it not possible for you to get the actual recycler view? And if you can't get it, then how will you trigger its onclick anyway?
2- Could you maybe share your code and where you need to do this?
disclaimer: I'm a bit new to android development, but I hope this helps.
To be thread safe you should use custom view action something like
#RunWith(AndroidJUnit4.class)
public class XXXXActivityTest {
int count=0;
#Test
public void xxxxxxx() throws Exception {
onView(allOf(withId(R.id.drawer_list))).perform(new ViewAction() {
#Override
public Matcher<View> getConstraints() {
return null;
}
#Override
public String getDescription() {
return null;
}
#Override
public void perform(UiController uiController, View view) {
count=((ListView)view).getAdapter().getCount();
}
});
}
}
then you can iterate with
onView(new RecyclerViewMatcher(R.id.drawer_list)
.atPositionOnView(0, R.id.your_item_body))
.perform(click());
assertThat(.......) for all items
We have a customised base class for creating a single cell inside a recyclerview:
public abstract class RecyclerViewItem<T extends RecyclerViewAdapter.ViewHolder> implements RecyclerViewItemInterface<T> {
#Override
public int getTypeId() {
return this.getClass().hashCode();
}
#Override
public T createViewHolder(ViewGroup parent) {
View v = LayoutInflater.from(parent.getContext()).inflate(getViewId(), parent, false);
try {
String className = ((ParameterizedType)getClass().getGenericSuperclass()).getActualTypeArguments()[0].toString().split("\\s")[1];
return (T)Class.forName(className).getConstructor(this.getClass(), View.class).newInstance(this, v);
} catch (Exception e) {
throw new RuntimeException("please create a viewholder accepting view as arg");
}
}
#Override
public void populateViewHolder(SdRecyclerViewAdapter.ViewHolder holder) {
onPopulateViewHolder((T) holder);
}
protected abstract int getViewId();
protected abstract void onPopulateViewHolder(T holder);
}
The interface:
public interface RecyclerViewItemInterface<T extends RecyclerViewAdapter.ViewHolder> {
int getTypeId();
T createViewHolder(ViewGroup parent);
void populateViewHolder(RecyclerViewAdapter.ViewHolder holder);
}
One of implementation of this class is using SimpleDraweeView to show image. I already set placeholder via:
holder.iconButton.getHierarchy().setPlaceholderImage(R.drawable.no_photo);
And if this cell has an image, display it:
mImageUrl = data.generateImageUrl();
if (mImageUrl != null) {
holder.iconButton.setImageURI(Uri.parse(imageUrl));
}
This correctly shows image for cell which has image. But if a cell has no image (mImageUrl null), it randomly shows image from another cell.
I know I can just type:
if (mImageUrl != null) {
holder.iconButton.setImageURI(Uri.parse(imageUrl));
} else {
holder.iconButton.setImageURI("res:/" + R.drawable.no_photo);
}
Could somebody explain to me why Fresco seems like randomly choose the image it want to display if I do not call .setImageURI()?
Thanks in advance.
I guess this happens because of view recycling. The recycler view re-uses an existing DraweeView, which still has the URL for the previous image set.
That's why instead of
mImageUrl = data.generateImageUrl();
if (mImageUrl != null) {
holder.iconButton.setImageURI(Uri.parse(mImageUrl));
}
you can just do
mImageUrl = data.generateImageUrl();
holder.iconButton.setImageURI(mImageUrl != null ? Uri.parse(mImageUrl) : null);
Suppose we have a list with several items. Each item has several fragments and a label within. When a user clicks on each label I need to change the text of the button1 that is out of the list view. How can I receive that label click event from inside of the list item and change a view that is out of the list view and list adapter.
I know how to handle internal events of the list view adapter inside the adapter. It's as simple as assigning the event handlers in GetView() method but they are not available out of the list.
Thanks for any help
Solved
I created a custom event and EventAgrs. When user clicks the label I invoke this event and in the main activity I handle the event and change the text of buton1. It was easier than I thought. In GetView() I assign the click event to the label_Click() event handler.
GetView(){
.
.
label.Click += label_Click();
.
.
}
In label_Click() I invoke the custom event that I have implemented before:
private void label_Click()(object sender, EventArgs e)
{
LabelClickedEvent.Invoke(sender, new LabelClickEventArgs("aaa", "bbb"));
}
In the list Adapter I declared this custom event: (For more information please look at this guide)
public event LabelClickedEventHandler LabelClickedEvent;
public delegate void LabelClickedEventHandler(object, sender,LabelClickEventArgs args);
public class LabelClickEventArgs : EventArgs
{
public string param1 { get; set; }
public string param2 { get; set; }
public LabelClickEventArgs(string param1 , string param2 )
{
this.param1 = param1 ;
this.param2 = param2 ;
}
}
In the main activity I simply assigned the event to my event handler and did whatever is needed.
listAdapter.LabelClickedEvent += listAdapter_LabelClickedEvent;
.
.
void listAdapter_LabelClickedEvent(object sender, TheListAdapter.LabelClickEventArgs args)
{
sendButton.Text = args.param1;
}
Hope it helps someone.
I do not know the proper way, but one way to do would be to implement the label item's OnClickListener() in the adapter, pass the reference of Button 1 to your adapter while creating an adapter, and then manipulate button 1 from OnClickListener().
public class MyAdapter extends BaseAdapter {
private Activity activity;
private ArrayList data;
private Button button1;
/************* CustomAdapter Constructor *****************/
public MyAdapter(Activity activity, ArrayList data, Button button1) {
this.data = data;
this.button1 = button1;
this.activity = activity;
inflater = (LayoutInflater) this.activity.
getSystemService(Context.LAYOUT_INFLATER_SERVICE);
}
public int getCount() {
if (data.size()<=0)
return 1;
return data.size();
}
public Object getItem(int position) {
return position;
}
public long getItemId(int position) {
return position;
}
public static class ViewHolder{
public TextView label1;
}
public View getView(int position, View convertView, ViewGroup parent) {
View vi = convertView;
ViewHolder holder;
if (convertView==null) {
vi = inflater.inflate(R.layout.list_item, null);
holder = new ViewHolder();
holder.label1 = (TextView)vi.findViewById(R.id.tvLabel1);
holder.label1.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
this.button1.setText("Label 1 clicked");
}
});
vi.setTag(holder);
} else {
holder = (ViewHolder)vi.getTag();
}
// show the data in the list view
return vi;
}
}
Suppose you have a button 1 in MainActivity outside list view, so when you create adapter in MainActivity
on your MainActivity's onCreate method do following:
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// define and initialize your data
Button button1 = (Button)findViewById(R.id.button1);
MyAdapter adapter = new MyAdapter(this, data, button1);
...
}
I have a form that when this form is submitted, I want to disable my textedit, would you please help me in this implementation,
Thanks in advance!
Here is part of my class that submitted button is:
public class MyForm extends PreferenceGroup implements View.OnClickListener {
if (isFormSubmited) {
submitter.disable();
FormField.buttonCatchButton.setText("View");
updateForm();
}
my button for disable the editTex
private void disable(ViewGroup layout) {
layout.setEnabled(false);
for (int i = 0; i < layout.getChildCount(); i++) {
View child = layout.getChildAt(i);
if (child instanceof ViewGroup) {
disable((ViewGroup) child);
} else {
child.setEnabled(false);
}
}
}
my onclick method in another class
public void onClick(View v) {
FormFragment formFragment = new FormFragment();
Bundle bundle = new Bundle();
bundle.putString(Constants_Args.ITEMS_KEY, itemsKey);
if (catchFormFile != null) {
bundle.putString(Constants_Args.CATCH_FORM_FILE_PATH, catchFormFile.getAbsolutePath());
}
if (catchFormJSONObject != null) {
bundle.putString(Constants_Args.CATCH_FORM_JSONOBJECT, catchFormJSONObject.toString());
}
if (catchSpeciesJSONArray != null) {
bundle.putString(Constants_Args.CATCH_SPECIES_JSONARRAY, catchSpeciesJSONArray.toString());
}
catchFormFragment.setArguments(bundle);
MainActivity mainActivity = (MainActivity)getContext();
mainActivity.pushFragment(formFragment);
}
My problem is that I don't know how to set: If form submitted, formFragment needs to let its child views that the field is disabled
I want to have a MvxSpinner with a drop down template that has a button in it. The button click brings up a webbrowser with information about that item. The button click works fine, but now the item cannot be selected. Is there a way around this?
I figured out a way to make this work. Not sure if it is best practices, but it works for me.
I made the ItemsSource for the Spinner an enumerable of view models. There is a command for the button click and an event to handle any other touches in the item. I subclassed MvxSpinner and MvxAdapter. In the subclassed adapter I assign the event to a handler that programmatically clicks the back button to close the drop down list. I also routed a method from the adapter to the spinner in order to set the selected item.
public class ButtonSpinner : MvxSpinner
{
public ButtonSpinner(Context context, IAttributeSet attrs) : base(context, attrs)
{
var adapter = new ButtonAdapter(context, routedItemClick);
adapter.ItemTemplateId = Adapter.ItemTemplateId;
adapter.DropDownItemTemplateId = Adapter.DropDownItemTemplateId;
adapter.SimpleViewLayoutId = Adapter.SimpleViewLayoutId;
this.Adapter = adapter;
}
private void routedItemClick(object sender, ItemClickEventArgs e)
{
this.SetSelection((int)sender);
}
}
public class ButtonAdapter : MvxAdapter
{
EventHandler<Android.Widget.AdapterView.ItemClickEventArgs> _routedItemClick;
View _parent;
public override IEnumerable ItemsSource {
get {
return base.ItemsSource;
}
set {
base.ItemsSource = value;
if (value != null)
{
foreach(var item in value)
{
var dialectItem = item as DialectItemViewModel;
dialectItem.DialectSelected += (object obj, EventArgs args) => {
var dialectItems = ItemsSource as List<DialectItemViewModel>;
_routedItemClick(dialectItems.IndexOf(dialectItem), null);
_parent.RootView.DispatchKeyEvent(new KeyEvent(KeyEventActions.Down, Keycode.Back));
_parent.RootView.DispatchKeyEvent(new KeyEvent(KeyEventActions.Up, Keycode.Back));
};
}
}
}
}
public ButtonAdapter(Context context, EventHandler<Android.Widget.AdapterView.ItemClickEventArgs> routedItemClick) : base(context)
{
_routedItemClick = routedItemClick;
}
protected override Android.Views.View GetView (int position, Android.Views.View convertView, Android.Views.ViewGroup parent, int templateId)
{
if (_parent == null)
_parent = parent;
return base.GetView (position, convertView, parent, templateId);
}
}