jitendra purohit
jitendra purohit

Reputation: 692

onTouchListener detecting wrong dynamically created cardview

I have just learnt how to create cardview dynamically. I'm using a button press to create a cardview and i have set onTouchListener to it. When i'm creating only one card onTouchListener is working perfectly but as soon as I'm creating one more card onTouchListener isn't working as expected. When I have 2 cards and I try to move 1st card it's moving 2nd one instead of 1st.

public class MainActivity extends AppCompatActivity
    implements NavigationView.OnNavigationItemSelectedListener {

Context context;
ImageView imageView;
RelativeLayout relativeLayout;
static int pos=0;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
    setSupportActionBar(toolbar);

    context=this;
    relativeLayout=(RelativeLayout)findViewById(R.id.rl_layout);

    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
            this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
    drawer.setDrawerListener(toggle);
    toggle.syncState();

    NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
    navigationView.setNavigationItemSelectedListener(this);
}



@Override
public void onBackPressed() {
    DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
    if (drawer.isDrawerOpen(GravityCompat.START)) {
        drawer.closeDrawer(GravityCompat.START);
    } else {
        super.onBackPressed();
    }
}

@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
}

@Override
public boolean onOptionsItemSelected(MenuItem item) {
    int id = item.getItemId();

    //noinspection SimplifiableIfStatement
    if (id == R.id.action_settings) {

        CreateCardViewWithoutImageView();

        return true;
    }

    return super.onOptionsItemSelected(item);
}

@SuppressWarnings("StatementWithEmptyBody")
@Override
public boolean onNavigationItemSelected(MenuItem item) {
    return true;
}

public void CreateCardViewWithoutImageView(){

    final CardView cardview=new CardView(context);

    cardview.setId(++pos);
    cardview.setLayoutParams((new CardView.LayoutParams(600, 600)));
    cardview.setContentPadding(25,25,25,25);
    cardview.setCardBackgroundColor(Color.MAGENTA);

    relativeLayout.addView(cardview);

}

private final View.OnTouchListener mListener = new View.OnTouchListener() {
    @Override
    public boolean onTouch(View card, MotionEvent event) {
        // The View (v) here is a CardView as the onTouchListener is set to it
        RelativeLayout.LayoutParams layoutParamsRL = (RelativeLayout.LayoutParams) ((CardView) card).getLayoutParams();
        float dx = 0, dy = 0, x = 0, y = 0;

        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                card.bringToFront();
                dx = event.getRawX() - layoutParamsRL.leftMargin;
                dy = event.getRawY() - layoutParamsRL.topMargin;
            }
            break;
            case MotionEvent.ACTION_MOVE: {
                x = event.getRawX();
                y = event.getRawY();
                layoutParamsRL.leftMargin = (int) (x - dx);
                layoutParamsRL.topMargin = (int) (y - dy);
                card.setLayoutParams(layoutParamsRL);
            }
            break;
            case MotionEvent.ACTION_UP: {

            }
            break;
        }
        return true;
    }
};

}

Upvotes: 0

Views: 246

Answers (3)

Eselfar
Eselfar

Reputation: 3869

It's because your cardview variable is global. So each time you create a new CardView it's replaced so the listener is always using the last CardView created. You should do something like:

// Note: By the way, you should NOT use a capital letter to name a function
public void createCardViewWithoutImageView(){

    //CardView
    final CardView cardview = new CardView(context);

    //....

}

You are going to have the same issue with layoutParamsRL as it should be local too.

EDIT

    // Context context; // You don't need to store the context here as you are in the activity
//    CardView cardview; // Don't need to be global
//    RelativeLayout.LayoutParams layoutParamsRL; // Don't need to be global
    ImageView imageView;
    RelativeLayout relativeLayout;
    static int pos = 0; // Are you sure it needs to be a static field?

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
        setSupportActionBar(toolbar);

//        context=this;
        relativeLayout = (RelativeLayout) findViewById(R.id.rl_layout);

        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        ActionBarDrawerToggle toggle = new ActionBarDrawerToggle(
                this, drawer, toolbar, R.string.navigation_drawer_open, R.string.navigation_drawer_close);
        drawer.setDrawerListener(toggle);
        toggle.syncState();

        NavigationView navigationView = (NavigationView) findViewById(R.id.nav_view);
        navigationView.setNavigationItemSelectedListener(this);
    }


    @Override
    public void onBackPressed() {
        DrawerLayout drawer = (DrawerLayout) findViewById(R.id.drawer_layout);
        if (drawer.isDrawerOpen(GravityCompat.START)) {
            drawer.closeDrawer(GravityCompat.START);
        } else {
            super.onBackPressed();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        int id = item.getItemId();

        //noinspection SimplifiableIfStatement
        if (id == R.id.action_settings) {

            createCardViewWithoutImageView();

            return true;
        }

        return super.onOptionsItemSelected(item);
    }

    @SuppressWarnings("StatementWithEmptyBody")
    @Override
    public boolean onNavigationItemSelected(MenuItem item) {
        return true;
    }

    public void createCardViewWithoutImageView() {

        //CardView
        CardView cardview = new CardView(MainActivity.this);

        cardview.setId(++pos);
        cardview.setLayoutParams((new CardView.LayoutParams(600, 600)));
        cardview.setContentPadding(25, 25, 25, 25);
        cardview.setCardBackgroundColor(Color.MAGENTA);
        cardview.setOnTouchListener(mListener);

        relativeLayout.addView(cardview);
    }

    private final View.OnTouchListener mListener = new View.OnTouchListener() {

        float dx, dy; // Moved outside the onTouch method in order to them to keep their value.

        @Override
        public boolean onTouch(View card, MotionEvent event) {
            Log.d("OnTouchListener", "don't touch me :p");

            // The View (v) here is a CardView as the onTouchListener is set to it
            RelativeLayout.LayoutParams layoutParamsRL = (RelativeLayout.LayoutParams) ((CardView) card).getLayoutParams();
            float x = 0, y = 0;

            switch (event.getAction()) {
                case MotionEvent.ACTION_DOWN: {
                    card.bringToFront();
                    dx = event.getRawX() - layoutParamsRL.leftMargin;
                    dy = event.getRawY() - layoutParamsRL.topMargin;
                }
                break;
                case MotionEvent.ACTION_MOVE: {
                    x = event.getRawX();
                    y = event.getRawY();
                    layoutParamsRL.leftMargin = (int) (x - dx);
                    layoutParamsRL.topMargin = (int) (y - dy);
                    card.setLayoutParams(layoutParamsRL);
                }
                break;
                case MotionEvent.ACTION_UP: {

                }
                break;
            }
            return true;
        }
    };

Upvotes: 1

ahmed shaaban
ahmed shaaban

Reputation: 116

//Create the Global object to make use of it in assign new property as u want

CardView selectedCardview;
@Override
protected void onCreate(Bundle savedInstanceState) { //....... }

//will create inner object

public void CreateCardViewWithoutImageView(){
    CardView cardview = new CardView(context);
    //Setting the default property u want:)
    cardview.setId(++pos);
    cardview.setLayoutParams((new CardView.LayoutParams(600, 600)));
    .......
    final CardView tempCardView=cardview;
    cardview.setOnTouchListener(new View.OnTouchListener() {
    @Override
    public boolean onTouch(View v, MotionEvent event) {
        switch(event.getAction())
        {
            case MotionEvent.ACTION_DOWN :
            {
              selectedCardview=tempCardView;
              .........and adding action as u want
            }
             ........... add another cases 
        }

    }
    ...........
}

now selectedCardview u use will represent the cardview u touch it and will be easy to set its property as it global

void setProperty(){
    /******** add what u want here********/
    selectedCardview.setBackgroundColor(Color.RED);
}

Upvotes: 0

ahmed shaaban
ahmed shaaban

Reputation: 116

1- the variable is global so u need to defined in inside method as mention above 2- you can easily change its properties with another method and pass it the cardview object as parameter 3- you can keep the global object to represent the selected cardview as in touchevent method will assign the cardview that fire event to the global and do what u want with it

Upvotes: 0

Related Questions