예제 #1
0
  /**
   * Recursive function to find all viable candidate combinations for laying out the next three
   * rows.
   */
  private void generateCombos(int imageIndex) {
    if (mCombosGenerated >= MAX_COMBOS) {
      // Consider a maximum of 30 combinations for any iteration of this.
      return;
    }

    if (mPartialCombo.size() == MAX_ROWS_PER_COMBO || imageIndex == mImageCount) {
      // If the partial combo contains max rows OR we are out of images, this combination
      // is complete.
      StringBuilder builder = null;
      if (DEBUG_COMBOS) {
        builder = new StringBuilder();
        builder.append('[');
        builder.append(mPartialCombo.computeScore());
        builder.append("] ");

        for (int i = 0; i < mPartialCombo.size(); i++) {
          if (i != 0) {
            builder.append(", ");
          }

          Row row = mPartialCombo.getRow(i);
          builder.append(row.startIndex());
          builder.append(" - ");
          builder.append(row.startIndex() + row.size() - 1);
        }
      }

      // Increment number of combos that have been generated.
      mCombosGenerated++;

      float scoreDiff =
          mBestCombo == null ? -1f : mPartialCombo.computeScore() - mBestCombo.computeScore();

      // Pseudo-randomly decide whether to select between combos of equal score.
      if (scoreDiff == 0f) {
        mSameScoreCount++;
        int randomInt = mRandom.nextInt(mSameScoreCount);
        scoreDiff = (randomInt == 0) ? -1 : 1;
      } else if (scoreDiff < 0f) {
        mSameScoreCount = 1;
      }

      if (scoreDiff < 0f) {
        // Found new best combo, so save it (as a clone, since the partial combo wil continue
        // to be modified during combo generation.
        mBestCombo = mPartialCombo.clone();
      }

      if (DEBUG_COMBOS) {
        if (scoreDiff < 0f) {
          // Indicate in the log that the combo was selected as current best.
          builder.append(" ***");
        }

        Log.d("DebugCombos", builder.toString());
      }

      return;
    }

    // For the current partial combination, compute possibilities for the next row.  We will
    // consider each row of ideal height, plus up to one overheight and one underheight row.
    Row row = new Row(imageIndex);
    int overHeightSize = 0;

    for (int i = imageIndex; i < mImageCount; i++) {
      // Add photo to next row under consideration.
      row.addImage();

      if (row.getAspect() < mMinRowAspect) {
        overHeightSize++;
      } else {
        // Add this row to the current partial combination and calculate the next set of
        // possible rows.
        mPartialCombo.addRow(row.clone());
        generateCombos(i + 1);
        mPartialCombo.removeRow();

        if (row.getAspect() > mMaxRowAspect) {
          break;
        }
      }
    }

    if (overHeightSize > 0) {
      mPartialCombo.addRow(new Row(imageIndex, overHeightSize));
      generateCombos(imageIndex + overHeightSize);
      mPartialCombo.removeRow();
    }
  }
예제 #2
0
  @Override
  protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
    // Fill any available width.
    int measuredWidth = MeasureSpec.getSize(widthMeasureSpec);

    // Don't re-measure everything unless width changes.
    if (mMeasuredWidth != measuredWidth) {
      mMeasuredWidth = measuredWidth;

      // From the full list of images, repeatedly carve off individual rows. Rows will be
      // selected to ensure a minimal amount of cropping while maintaining the aspect ratio of
      // each individual bitmap.
      int imageIndex = 0;
      while (imageIndex < mImageCount) {
        // To determine the next row, lay out the next three rows in ideal fashion and take the
        // first row.
        // This is accomplished by calculating a number of possible combinations for the next three
        // rows
        // and scoring each combination.  The first row of the highest scoring combination will be
        // accepted.
        Assert.assertTrue(mPartialCombo.size() == 0);
        mBestCombo = null;
        mCombosGenerated = 0;
        mSameScoreCount = 0;

        if (DEBUG_COMBOS) {
          Log.d("DebugCombos", "ROW #" + (mLayoutRows.size() + 1));
        }

        generateCombos(imageIndex);

        // Add first row from highest scoring combo to the list of rows for layout.
        Row row = mBestCombo.getRow(0);
        mLayoutRows.add(row);

        // Skip past images that are already laid out.
        imageIndex += row.size();
      }

      // Calculate total height by adding together height of all rows.
      mMeasuredHeight = 0;

      for (int i = 0; i < mLayoutRows.size(); i++) {
        Row row = mLayoutRows.get(i);
        row.measure(mMeasuredWidth);
        mMeasuredHeight += row.getMeasuredHeight();
        mMeasuredHeight += mBorderSize;
      }
    }

    // Height may be constrained by container.
    int measuredHeight = mMeasuredHeight;
    switch (MeasureSpec.getMode(heightMeasureSpec)) {
      case MeasureSpec.AT_MOST:
        measuredHeight = Math.min(mMeasuredHeight, MeasureSpec.getSize(heightMeasureSpec));
        break;

      case MeasureSpec.EXACTLY:
        measuredHeight = MeasureSpec.getSize(heightMeasureSpec);
        break;
    }

    setMeasuredDimension(measuredWidth, measuredHeight);
  }