简体   繁体   中英

Custom View Scrolling issues Android

I've been designing an application that requires the use of a scrollbar on a custom view. The problem that I have run into is that my custom view's height will constantly change when new items are added by the user. I suspect that this isn't a very unusual problem, but to complicate things, I'm not actually adding new objects to my custom view, I'm just drawing Bitmap images on the canvas. The reason this is troublesome to me is when Android inflates the layout, it sets the size to be whatever I tell it (0dip) and as I add the Bitmaps, it simply changes the size to fill the Scrollview; thereby, whenever the Custom View draws an image beyond the current height constraints, instead of scrolling, the app simply cuts the picture off to maintain the current height.

(This is for a card game app, so I wanted to fan out your current deck in a easy to view and edit fashion.)

Here is the relevant code:

public class DeckEdit extends Activity implements FilterQueryProvider  {

static final int PROGRESS_DIALOG = 0;
private Deck deck;
private CardListAdapter lstAdpt;
private ArrayList<CardImage> cards;
private ProgressDialog progressDialog;
private ProgressThread progressThread;
private String[] cardList;
private DeckEditCardView deckGrid;
private ScrollView sc;
protected Cursor cursor;

private EditText filterText = null;
ArrayAdapter<String> adapter = null;

public void onCreate(Bundle savedInstanceBundle){
    super.onCreate(savedInstanceBundle);
    deck = new Deck();
//This is what stores the Card Images that I draw to the canvas with
    cards = new ArrayList<CardImage>();

    setContentView(R.layout.deck_edit_layout);

    sc = (ScrollView) findViewById(R.id.deck_scroller);
    deckGrid = (DeckEditCardView) findViewById(R.id.deck_grid);

    filterText = (EditText) findViewById(R.id.card_search_box);
    filterText.addTextChangedListener(filterTextWatcher);


    pickDeck();
}

And then this is called after I load the deck

private void finishSetup(){
    //this is where I set up the deckGrid to have all the cards and then
    deckGrid.setCards(cards);
    //draw them to the screen
    deckGrid.invalidate();
    //This is where I realized that the height value might be causing the problem
    Log.d("finishSetup()", "deckGrid width: "+deckGrid.getWidth());
    Log.d("finishSetup()", "deckGrid height: "+deckGrid.getHeight());
}

The DeckEditCardView class contains this

public class DeckEditCardView extends View implements OnTouchListener {
private ArrayList<CardImage> cards;

private int X_COLS;
@SuppressWarnings("unused")
private int Y_ROWS;
private final int COL_WIDTH;
private final int ROW_HEIGHT;
private Context context;

private final int X_PADDING = 2;
private final int Y_PADDING = 2;
private final int X_CARD_OVERLAY = 7;
private final int Y_CARD_OVERLAY = 5; 


public DeckEditCardView(Context context) {
    super(context);
    cards = new ArrayList<CardImage>();
    int cardWidth = getResources().getDrawable(R.drawable.back).getIntrinsicWidth();
    int cardHeight = getResources().getDrawable(R.drawable.back).getIntrinsicHeight();
    COL_WIDTH = (X_PADDING+(X_CARD_OVERLAY*3)+cardWidth);
    Log.d("DECV","COLWIDTH 1: "+COL_WIDTH);
    ROW_HEIGHT = (Y_PADDING+(Y_CARD_OVERLAY*3)+cardHeight);
    Log.d("DECV","ROWE_HEIGHT 1: "+ROW_HEIGHT);
}

public DeckEditCardView(Context context, AttributeSet attrs) {
    super(context, attrs);
    cards = new ArrayList<CardImage>();

    int cardWidth = getResources().getDrawable(R.drawable.back).getIntrinsicWidth();
    int cardHeight = getResources().getDrawable(R.drawable.back).getIntrinsicHeight();
    COL_WIDTH = (X_PADDING+(X_CARD_OVERLAY*3)+cardWidth);
    Log.d("DECV","COLWIDTH 2 : "+COL_WIDTH);
    ROW_HEIGHT = (Y_PADDING+(Y_CARD_OVERLAY*3)+cardHeight);
    Log.d("DECV","ROWE_HEIGHT 2: "+ROW_HEIGHT);
}

/*
public DeckEditCardView(Context context, AttributeSet attrs, int defStyle) {
    super(context, attrs, defStyle);
    cards = new ArrayList<CardImage>();
    int width = getWidth();
    int height = getHeight();
    int cardWidth = getResources().getDrawable(R.drawable.back).getIntrinsicWidth();
    int cardHeight = getResources().getDrawable(R.drawable.back).getIntrinsicHeight();
    COL_WIDTH = (X_PADDING+(X_CARD_OVERLAY*3)+cardWidth);
    Log.d("DECV","COLWIDTH 3: "+COL_WIDTH);
    ROW_HEIGHT = (Y_PADDING+(Y_CARD_OVERLAY*3)+cardHeight);
    Log.d("DECV","ROWE_HEIGHT 3: "+ROW_HEIGHT);
    X_COLS = (width/COL_WIDTH);
    Y_ROWS = (height/ROW_HEIGHT);

}
*/    
@Override
public void onFinishInflate(){
    super.onFinishInflate();
    //this.
}

public void onSizeChanged(int w, int h, int oldw, int oldh){
    int width = getWidth();
    int height = getHeight();
    X_COLS = (width/COL_WIDTH);
    Y_ROWS = (height/ROW_HEIGHT);

}



public Point getNextCardPoint(Point curP, boolean sameCard){
    Point p=null;
    if (sameCard)
        p = new Point(curP.x+X_CARD_OVERLAY,curP.y+Y_CARD_OVERLAY);
    else { //need to be on the same column
        if (point2Col(curP)+1<X_COLS)
            p = new Point(COL_WIDTH*(point2Col(curP)+1)+X_PADDING,
                ROW_HEIGHT*(point2Row(curP))+Y_PADDING);
        else {//add to new column
            if (point2Row(curP)+1 > Y_ROWS)
                Y_ROWS++;

            p = new Point(X_PADDING,
                    ROW_HEIGHT*(point2Row(curP)+1)+Y_PADDING);
        }
    }
    return p;
}

public void setCards(ArrayList<CardImage> cards){
    this.cards = cards;
}

private int point2Col(Point p){
    return p.x / COL_WIDTH;
}
private int point2Row(Point p){
    return p.y / ROW_HEIGHT;
}


@Override
protected void onDraw(Canvas canvas) {
    super.onDraw(canvas);
    //ScrollView s = new ScrollView(context);
    //s.addView(canvas);
    int length = cards.size();
    CardImage c;
    for (int i = 0; i < length; i++) {
        //Log.d("onDraw", "output a card");
        c = cards.get(i);
        canvas.drawBitmap(c.getBitmap(), c.getX(), c.getY(), null);
    }
}

@Override
public boolean onTouch(View arg0, MotionEvent arg1) {
    // TODO Auto-generated method stub
    return false;
}
}

So in conclusion, I don't know how to allow the user to scroll and see the cards that don't fit on the screen (its almost guaranteed that a fully built deck will take a scrollbar to see all of them. At most with this code it'll put in all the card images I need, but the ones that go of screen I don't know what to do:/

And lastly my Layout.xml file

<com.xeroxchange.ydd.DeckEditCardView android:layout_weight="2" 
     android:id="@+id/deck_grid" 
     android:layout_width="fill_parent" 
     android:layout_height="0dip"></com.xeroxchange.ydd.DeckEditCardView>
</ScrollView>       
<LinearLayout android:layout_weight="1" 
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:orientation="vertical" >

        <!-- Pretty hint text, and maxLines -->
<EditText android:id="@+id/card_search_box" 
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:hint="type to filter"
    android:inputType="text"
    android:maxLines="1"/>

    <!-- Set height to 0, and let the weight param expand it -->
    <!-- Note the use of the default ID! This lets us use a 
         ListActivity still! -->
    <ListView android:id="@+id/card_list"
        android:layout_width="fill_parent"
        android:layout_height="0dip"
        android:layout_weight="2" 
    /> 

</LinearLayout>

</LinearLayout>

Your layout doesn't work properly because the DeckEditCardView doesn't measure itself. You must override the View.onMeasure() method in the DeckEditCardView class and set measured size depending on view's content. In your layout xml file you must specify wrap_content as a height of the DeckEditCardView .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM