Fragment seems to inflate wrong view - android-fragments

I'm currently trying to program an Android Launcher with Fragments but I have problems with the Views on the Fragments.
I have a Dock-Fragment with a Dock-Controller which allow the user to change fragments, such as apps menu, settings fragment etc. The Dock is displayed on the buttom of the display, the Fragments(apps menu, settings fragment) should be displayed above the Dock.
The problem is, that the apps menu is not shown in its associated Fragment but rather in the Dock Fragment behind the dock icons,... So I guess, the app menu fragment gets the wrong view in its onCreateView()-Method, but I don't get why.
This is the code of the MainActivity that extends from FragmentActivity. I add the fragments to the manager.
private void addDockToManager() {
FragmentManager fm = getSupportFragmentManager();
FragmentTransaction ft = fm.beginTransaction();
ft.add(dbConnection.getLayout(DOCK_TAG), dockController.getFragment(), DOCK_TAG);
ft.commit();
}
private void addPluginsToManager() {
FragmentManager fm = null;
FragmentTransaction ft = null;
for(String key : controllerMap.keySet()) {
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
FrameController controller = null;
if ((controller = controllerMap.get(key)) != null) {
ft.add(dbConnection.getLayout(key), controller.getFragment(), key);
if (key.equals(standardFrame))
ft.addToBackStack(key);
}
ft.commit();
fm.executePendingTransactions();
}
fm = getSupportFragmentManager();
ft = fm.beginTransaction();
for(String key : controllerMap.keySet()) {
if (controllerMap.get(key) != null && !key.equals(standardFrame)) {
ft.hide(fm.findFragmentByTag(key));
}
}
ft.commit();
}
The layouts are hardcoded at the moment in dbConnection:
public int getLayout(String name) {
int layout = -1;
switch(name) {
case "app_menu" : layout = R.id.fl_app_menu;
case "settings" : layout = R.id.fl_settings;
case "dock" : layout = R.id.fl_dock;
}
return layout;
}
The MainActivity's xml looks like that:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/rl_container"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context="com.activity.MainActivity"
tools:ignore="MergeRootFrame" >
<FrameLayout
android:id="#+id/fl_settings"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="#+id/fl_dock"
android:background="#00ffffff" >
</FrameLayout>
<FrameLayout
android:id="#+id/fl_app_menu"
android:layout_width="match_parent"
android:layout_height="400dp"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_alignParentTop="true"
android:layout_above="#+id/fl_dock"
android:background="#00ffffff" >
</FrameLayout>
<FrameLayout
android:id="#+id/fl_dock"
android:layout_width="match_parent"
android:layout_height="70dp"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true" >
</FrameLayout>
</RelativeLayout>
The xml of the apps menu is a gridview and looks like that:
<GridView xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/gv_apps"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="6"
android:gravity="center"
android:columnWidth="50dp"
android:stretchMode="columnWidth" >
</GridView>
The App Fragment looks like that:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup group,
Bundle savedInstanceState) {
view = inflater.inflate(R.layout.external_apps, group, false);
layout = (GridView) view.findViewById(R.id.gv_apps);
return view;
}
#Override
public void onActivityCreated(Bundle savedInstanceState) {
super.onActivityCreated(savedInstanceState);
GridViewAdapter gridViewAdapter = new GridViewAdapter((AppMenuController) myController, apps);
((GridView) layout).setAdapter(gridViewAdapter);
}
And the getView Method of the GridViewAdapter:
#Override
public View getView(int position, View convertView, ViewGroup parent) {
ImageView imageView = new ImageView(controller.getMainActivity().getApplicationContext());
imageView.setImageDrawable(buttons.get(position).getIcon());
imageView.setLayoutParams(new GridView.LayoutParams(65, 65));
return imageView;
}
I hope what I mentioned is enough to resolve the problem. I am searching the web for hours but I found no solution.

It's a much simpler problem than that I think.
public int getLayout(String name) {
int layout = -1;
switch(name) {
case "app_menu" : layout = R.id.fl_app_menu;
case "settings" : layout = R.id.fl_settings;
case "dock" : layout = R.id.fl_dock;
}
return layout;
}
Should be:
public int getLayout(String name) {
int layout = -1;
switch(name) {
case "app_menu" :
layout = R.id.fl_app_menu;
break;
case "settings" :
layout = R.id.fl_settings;
break;
case "dock" :
layout = R.id.fl_dock;
break;
}
return layout;
}
Because switch-case structure is still essentially just an organized goto, and not actually an if-else structure, aka if you don't break out, then all cases will run sequentially.

I found the problem. And it was in a part of the code I never expected it to be.
The Dummy-Switch-Case in dbConnection caused it. Seemingly Strings aren't compared by value but rather by reference in such a Switch-Case. So it always chose the dock container layout to be associated with the app menu in the fragment manager,...

Related

Overlapping of fragments when transiting on clicking on an item in RecyclerView of one fragment to another new fragment

I am new to android development. The problem is the RecyclerView populated using a firebase database is not replaced by a new fragment, rather the new fragment is on top, but clicking on another item of the recycler view still works, which I checked using a toast in the new fragment. I know that the next fragment is there because I have TextView at the bottom, which is visible on clicking on the recycler view Item.
Here is my code
adapter = new FirebaseRecyclerAdapter<Categories, CategoryViewHolder>(options) {
#Override
protected void onBindViewHolder(#NonNull final CategoryViewHolder holder, int position, #NonNull Categories model)
{
Picasso.get().load(model.getImage()).placeholder(R.drawable.camera).into(holder.categoryImage, new Callback() {
#Override
public void onSuccess()
{
}
#Override
public void onError(Exception e) {
Toast.makeText(getContext(), e.getMessage(), Toast.LENGTH_SHORT).show();
}
});
holder.categoryName.setText(model.getName());
holder.categoryImage.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(getContext(), holder.categoryName.getText().toString(), Toast.LENGTH_SHORT).show();
// Intent intent = new Intent(getActivity(), ProductListActivity.class);
// startActivity(intent);
AppCompatActivity activity = (AppCompatActivity) view.getContext();
SearchFragment fragment = SearchFragment.newInstance(holder.categoryName.getText().toString());
FragmentManager fragmentManager = activity.getSupportFragmentManager();
FragmentTransaction fragmentTransaction = fragmentManager.beginTransaction();
fragmentTransaction.replace(R.id.nav_host_fragment, fragment, SearchFragment.class.getSimpleName());
fragmentTransaction.addToBackStack(null);
fragmentTransaction.commit();
}
});
The fragment I am using is also used for the navigation drawer using navController.
<?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"
app:layout_behavior="#string/appbar_scrolling_view_behavior"
tools:showIn="#layout/app_bar_main">
<fragment
android:id="#+id/nav_host_fragment"
android:name="androidx.navigation.fragment.NavHostFragment"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:defaultNavHost="true"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:navGraph="#navigation/mobile_navigation" />
</RelativeLayout>
Edit: I have another recyclerView inside SearchFragment, which didn't show after I clicked an image in the RecyclerView(One which calls SearchFragment). But it showed after I minimized and opened the app again. I don't understand why that is happening.
I just found an easy way to move from one fragment to another without using FragmentManager. I hope this helps others, it worked for me. Initialize the NavController in the first fragment inside onCreateView
navController = Navigation.findNavController(getActivity(), R.id.nav_host_fragment);
And adding the following for transition
Bundle bundle = new Bundle();
bundle.putString("Category", holder.categoryName.getText().toString());
navController.navigate(R.id.nav_category_product_list, bundle);
to get the argument in the moving fragment type this
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setHasOptionsMenu(true); //To get menu items at the top
if (getArguments() != null) {
Category = getArguments().getString("Category");
}
}
Also, add this transition in Navigation graph XML
.
.
.
<fragment
android:id="#+id/nav_category"
android:name="com.grocery.admin.ui.category.CategoryFragment"
android:label="#string/menu_category"
tools:layout="#layout/fragment_category" >
<action
android:id="#+id/action_nav_category_to_nav_category_product_list"
app:destination="#id/nav_category_product_list" />
</fragment>
<fragment
android:id="#+id/nav_category_product_list"
android:name="com.grocery.admin.ui.category.CategoryProductFragment"
android:label="Product List"
tools:layout="#layout/fragment_category_product">
</fragment>
.
.
.

MVVMCross Fragment and dynamically setting event commands

I have a MvxFragment that is bound to a view model that has two ICommand properties defined. This fragment contains an MvxListView and can be part of different activities/layouts dependant on the device size/orientation.
What I want to know is how to specify the ItemClick event command of the MvxBind property of the MvxListView dynamically or is there a better way to handle this use case? Should I use a separate fragment?
A similar use case to the one I am trying to achieve is within the Overview section of this Xamarin Dev Guide
View
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:local="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<MvxListView
android:layout_width="match_parent"
android:layout_height="wrap_content"
local:MvxBind="ItemsSource Courses; ItemClick Comamnd1"
local:MvxItemTemplate="#layout/coursetemplate" />
</LinearLayout>
ViewModel (Simpified)
public class MyViewModel : MvxViewModel
{
private MvxCommand<MyMessage> messageCommand;
public MyViewModel (IMvxMessenger messenger, IHttpClientBuilderService httpClientBuilder)
{
this.httpClientBuilder = httpClientBuilder;
this.messenger = messenger;
}
public ICommand Comamnd1 {
get { return new MvxCommand<Course> ((c) => ShowViewModel<MyOtherViewModel>(c)); }
}
public ICommand Command2 {
get
{
messageCommand = messageCommand ?? new MvxCommand<MyMessage>(c =>
{
var message = new MyMessage(this, c);
messenger.Publish(message);
});
return selectedCourse;
}
}
}
OK, you can do this my overriding the OnActivityCreated event for the fragment as below.
public override void OnActivityCreated (Bundle savedInstanceState)
{
base.OnActivityCreated (savedInstanceState);
MvxListView list = Activity.FindViewById<MvxListView>(Resource.Id.[theID]);
if (Activity.FindViewById<View>(Resource.Id.[fragmentID]) != null)
list.ItemClick = ((MyViewModel)ViewModel).Command1;
else
list.ItemClick = ((MyViewModel)ViewModel).Command2;
}
You can pull out the list by using the Activity.FindViewById function and then set the appropraite ICommand or IMvxCommand from the ViewModel via the list.ItemClick event

RecyclerView scroll to position and get that view

I want to auto scroll a list item to top (firstVisible item) in my recycler view and get the view at that position, so I can highlight it, from my fragment.
So, this is the gist of my fragment code :
private void activateNewListItem(int position) {
mLayoutManager().scrollToPositionWithOffset(position, 0);
RecyclerView.ViewHolder viewHolder = mRecyclerView.findViewHolderForLayoutPosition(position);
View view = viewHolder.getItemView();
view.setBackgroundColor(getResources().getColor(R.color.esr_light_grey));
}
If position is 1,2,3,4 etc, mRecyclerView.findViewHolderForPosition(position) returns a valid ViewHolder,
because I guess RecyclerView has drawn ViewHolders for those indexes in dataSet.
However, if I pass in position as say, 25, mRecyclerView.findViewHolderForPosition(position) returns null, because I assume, it hasn't been drawn yet, even thoughI called mLayoutManager.scrollToPositionWithOffset(position, 0) above it.
What can I do to achieve these two things?
Scroll the list item of dataSet index position to firstVisibleItem.
Get the View or ViewHolder object of that listItem, so I can change the background or whatever.
Instead of accessing ViewHolder somewhere else, go for a custom selector background in your adapters item layout xml file instead, track the position in your adapter as selected position and call notifydatasetchanged()/notifyItemRangeChanged() to highlight it once the scroll is complete. You already have the scrollToPosition() method, have a scroll listener to track the scroll state.
Example for selector background : item_selector.xml
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android=
"http://schemas.android.com/apk/res/android">
<item android:state_activated="true"
android:drawable="#color/primary_dark" />
<item android:drawable="#android:color/transparent" />
</selector>
Set it as background to your item xml
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/container_list_item"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/item_selector">
<--- Your layout items here --->
</RelativeLayout>
Your adapter code :
public class SampleAdapter extends RecyclerView.Adapter<SampleAdapter.ViewHolder> {
private final String[] list;
private int lastCheckedPosition = -1;
public SampleAdapter(String[] list) {
this.list = list;
}
#Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View view = View.inflate(parent.getContext(), R.layout.sample_layout, null);
ViewHolder holder = new ViewHolder(view);
return holder;
}
#Override
public void onBindViewHolder(ViewHolder holder, int position) {
holder.choiceName.setText(list[position]);
holder.containerView.setSelected(position == lastCheckedPosition);
}
#Override
public int getItemCount() {
return list.length;
}
public class ViewHolder extends RecyclerView.ViewHolder {
#Bind(R.id.choice_name)
TextView choiceName;
#Bind(R.id. container_list_item)
View containerView;
public ViewHolder(View itemView) {
super(itemView);
ButterKnife.bind(this, itemView);
itemView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
lastCheckedPosition = getAdapterPosition();
notifyItemRangeChanged(0, list.length);
}
});
}
}
}
To scroll to any position :
recyclerview.scrollToPosition(position)
Let me know if this helps.
It takes some seconds to update the ViewHolder Information. Just scroll and delay the mRecyclerView.findViewHolderForLayoutPosition call for some milliseconds (100ms sounds reasonable)
Put this code in your fragment where you are going to scroll to the first RecyclerView item:
RecyclerView.ViewHolder holder = mRecyclerView
.findViewHolderForAdapterPosition(0);
while (holder == null) {
int firstVisiblePosition = mLayoutManager()
.findFirstCompletelyVisibleItemPosition();
RecyclerView.ViewHolder firstVisibleHolder = mRecyclerView
.findViewHolderForAdapterPosition(firstVisiblePosition);
View v = firstVisibleHolder.getItemView();
if (v != null) mRecyclerView.scrollBy(0, (int) v.getY());
else break;
holder = mRecyclerView.findViewHolderForAdapterPosition(0);
}
View view = null;
if (holder != null) view = holder.getItemView();
if (view != null) mRecyclerView.scrollBy(0, (int) view.getY());

getChildFragmentManager() and viewpager

I have the same problem as Navigating back to FragmentPagerAdapter -> fragments are empty but would like some clarification on the solution of using getChildFragmentManager().
This solution uses getChildFragmentManager(), the manager for fragments inside this Fragment(OuterFragment, which has the viewpager). InnerFragment is a page inside OuterFragment. When someone clicks the listview in InnerFragment, I want InnerFragment2 to replace InnerFragment. What do the xml and fragment managers look like?
fragment_outer.xml:
<?xml version="1.0" encoding="utf-8"?>
<android.support.v4.view.ViewPager
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/vpPager"
android:layout_height="wrap_content"
android:layout_width="match_parent">
<android.support.v4.view.PagerTabStrip
android:id="#+id/pager_header"
android:layout_gravity="top"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:paddingBottom="4dp"
android:paddingTop="4dp" />
<FrameLayout
android:id="#+id/inner_content"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</android.support.v4.view.ViewPager>
OuterFragment.java:
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
View v = inflater.inflate(R.layout.fragment_outer, container, false);
vpPager = (ViewPager) v.findViewById(R.id.vpPager);
FragmentManager cfManager = getChildFragmentManager();
adapterViewPager = new MyPagerAdapter(cfManager);
vpPager.setAdapter(adapterViewPager);
return v;
}
public static class MyPagerAdapter extends FragmentPagerAdapter {
public MyPagerAdapter(FragmentManager fragmentManager) {
super(fragmentManager);
}
#Override
public int getCount() {
return 2;
}
// Returns the fragment to display for that page
#Override
public Fragment getItem(int position) {
switch (position) {
case 0:
return InnerFragment.newInstance(false);
case 1:
return InnerFragment.newInstance(true);
default:
return null;
}
}
InnerFragment shows up as a fragment inside OuterFragment, which has the viewpager. InnerFragment has a listview that when clicked, should replace InnerFragment with InnerFragment2.
InnerFragment.java:
FragmentManager fm = getChildFragmentManager();
fm = fm.beginTransaction();
ft.addToBackStack(null);
ft = ft.replace(R.id.inner_content,
InnerFragment2.newInstance(someArg));
ft.commit();
This throws an error saying InnerFragment2 does not recognize view R.id.inner_content.
Not only should InnerFragment2 replace InnerFragment, but when InnerFragment2 is shown and it's button is clicked, I want InnerFragment2 replaced with InnerFragment3. I basically want to use inner_content as an inner container and keep adding fragments to a backstack for appropriate back behavior.
Do I getChildFragmentManager() or getFragmentManager() each time I add to my fragment backstack, what does the xml pattern look like, because having one framelayout in my outerfragment isn't doing it.
public void setupViewPager(ViewPager viewPager) {
FragmentManager cfManager=getChildFragmentManager();
viewPagerAdapter = new ViewPagerAdapter(cfManager);
// viewPagerAdapter = new ViewPagerAdapter(getActivity().getSupportFragmentManager());
viewPagerAdapter.addFragment(new EntertainmentWallpaperFragment(), getString(R.string.title_entertainment_wallpapers));
viewPagerAdapter.addFragment(new EntertainmentMusicFragment(), getString(R.string.title_entertainment_music));
viewPagerAdapter.addFragment(new EntertainmentGamesFragment(), getString(R.string.title_entertainment_games));
viewPagerAdapter.addFragment(new EntertainmentEBooksFragment(), getString(R.string.title_entertainment_ebooks));
viewPagerAdapter.addFragment(new EntertainmentAppsFragment(), getString(R.string.title_entertainment_apps));
viewPager.setAdapter(viewPagerAdapter);
}
I hope this helps. I had the same problem where the fragments apear but once you go back they dissapear and find an empty fragent. Commnented the line that I had first implemented which after updating the fragment manager I was able to enjoy free smooth scroll.

Getting multiple item with one touch in GridView

I have a gridview with custom buttons called bg_button in each cell. I am trying to create a boggle-like game and still a newbie in Android. I was searching through internet about this issue over a week now and still got nothing.
The issue is, when a touch_down I can get the specific item without any problem but when I start to move diagonal, I get multiple grid items that I do not want. For example;
A O F T
K T U L
T R S V
J O K U
The grid that I have above, when I touch T and then trying to move to O, I get;
T -> J -> O or T -> R -> O
I do not want J or R, but still I am touching that as well. I have tried to change to padding, or vertical and horizontal spacing but the issue remained the same. Could you please help me about this issue or at least can you give me a way to do this, or at least a specific tag that I can google and find information that can help me? Thank you so much for your time.
This is the part of my code for the touch event. I am saving the path to an ArrayList and I am sorry for the messy code. I will clean once I finish hardcoding:
final ArrayList<Integer> myList = new ArrayList<Integer>();
gridView = (GridView) this.findViewById(R.id.gridFriends);
MyAdapter gridAdapter = new MyAdapter(Boggler.this,board_1d);
gridView.setAdapter(gridAdapter);
gridView.setOnTouchListener(new View.OnTouchListener(){
#Override
public boolean onTouch(View v, MotionEvent event) {
final GridView layout = (GridView)v;
int action = event.getActionMasked();
float currentXPosition = event.getX();
float currentYPosition = event.getY();
int position = gridView.pointToPosition((int) currentXPosition, (int) currentYPosition);
// position = layout.pointToPosition( (int)event.getX(), (int)event.getY() );
while(position == -1)
position=event.getAction();
View v2 =layout.getChildAt(position);
myList.add(position);
Bg_button bt = (Bg_button) v2.findViewById(R.id.grid_item);
bt.setPressed(true);
Log.d(this.getClass().getName(), String.format("Over view.id[%d]", position));
if (action == MotionEvent.ACTION_MOVE){
myList.add(position);
return true;
}
if (action == MotionEvent.ACTION_UP) {
Log.d(this.getClass().getName(), myList.toString());
int i=0,j=0;
int state = 0;
Object[] st = myList.toArray();
for (Object s : st) {
if (myList.indexOf(s) != myList.lastIndexOf(s)) {
myList.remove(myList.lastIndexOf(s));}
else {
v2 =layout.getChildAt(myList.get(myList.lastIndexOf(s)));
bt = (Bg_button) v2.findViewById(R.id.grid_item);
bt.setPressed(false);
name = name + bt.getText();
Log.d(this.getClass().getName(), name);
}
}
And this is the xml files that I am using button_boggler:
<?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/com.example.proje_test.bg_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<com.example.proje_test.Bg_button
android:id="#+id/grid_item"
android:layout_width="80dp"
android:layout_height="80dp"
android:layout_gravity="center"
android:clickable="false"
android:textAppearance="?android:attr/textAppearanceMedium"
android:background="#drawable/color_bg_selector"
android:textSize="50dp"
/>
</LinearLayout>
And activity_boggler:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:ads="http://schemas.android.com/apk/lib/com.google.ads"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:gravity="center"
android:orientation="vertical" >
<GridView
android:id="#+id/gridFriends"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="top"
android:clipChildren="true"
android:columnWidth="100dp"
android:gravity="center"
android:numColumns="4"
android:scrollbars="none"
android:stretchMode="columnWidth" >
</GridView>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAppearance="?android:attr/textAppearanceLarge"
android:text="Large Text"
android:id="#+id/feedback"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true" />
</LinearLayout>
I have found a solution that is working for me. I have seen a couple of same questions about this kind of issues without answers because of that I will answer my own question so maybe it can help those who have this kind of issues. I made custom button class with different attrs called Bg_button:
public class Bg_button extends Button {
private static final int[] STATE_C = {R.attr.state_chosen};
private static final int[] STATE_R = {R.attr.state_right};
private static final int[] STATE_W = {R.attr.state_wrong};
public boolean mIschosen = false;
public boolean mIsright = false;
public boolean mIswrong = false;
public Bg_button(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
protected int[] onCreateDrawableState(int extraSpace) {
final int[] drawableState = super.onCreateDrawableState(extraSpace + 3);
if (mIschosen) {
mergeDrawableStates(drawableState, STATE_C);
}
if (mIsright) {
mergeDrawableStates(drawableState, STATE_R);
}
if (mIswrong) {
mergeDrawableStates(drawableState, STATE_W);
}
return drawableState;
}
public void setchosen(boolean ischosen) {mIschosen = ischosen;
refreshDrawableState();}
public void setright(boolean isright) {mIsright = isright;
refreshDrawableState();}
public boolean setwrong(boolean iswrong) {mIswrong = iswrong;
refreshDrawableState();
return true;}
#Override
public void getHitRect(Rect outRect) {
outRect.set(getLeft() + 20, getTop() + 20, getRight() - 20, getBottom() - 20);
}
}
So the solution I have found is limiting the touch area of the button so they do not intercept. I don't know how ethical this is but it is working for me now.
#Override
public void getHitRect(Rect outRect) {
outRect.set(getLeft() + 20, getTop() + 20, getRight() - 20, getBottom() - 20);
}
}
This is the best answer I can come up with so far. I limited the touch area of button to its center with reversing the transaction that we do for expanding it. And the 3 lines code above did the trick. I hope this helps.

Resources