I am trying to draw a level on top of a background, but I am unsure how to do it. I am able to draw each of the pieces separately, but am completely lost on how to draw both on the screen. I believe I may have to draw the background with a different method, but I don't know of such a method.
Here is my code thus far:
public class DisplayMap extends Activity {
ImageView mapView;
String FILENAME = "World.tmx";
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.activity_main);
setContentView(new TileBackground(this));
}
public void loadWorld(String path) {
ImageView mapView;
// Start the parser, get back TMX data object
TileMapData t = TMXLoader.readTMX(FILENAME, this);
mapView = (ImageView) findViewById(R.id.MapImage);
// Create a Bitmap from the tilemap data
Bitmap mapImage = TMXLoader.createBitmap(t, this, 0, t.layers.size());
// Set the imageview to show the map, if we have one
if (mapImage != null) {
mapView.setImageBitmap(mapImage);
}
// Map loading problem, inform the user.
else {
Toast errorMessage = Toast.makeText(getApplicationContext(),
"Map could not be loaded", Toast.LENGTH_LONG);
errorMessage.show();
}
}
class TileBackground extends View {
Bitmap bg;
public TileBackground(Context context) {
super(context);
try {
AssetManager assetManager = context.getAssets();
InputStream inputStream;
inputStream = assetManager.open("Background.png");
BitmapFactory.Options options = new BitmapFactory.Options();
options.inPreferredConfig = Bitmap.Config.ARGB_4444;
bg = BitmapFactory.decodeStream(inputStream, null, options);
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
#Override
public void onDraw(Canvas canvas) {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
int width = size.x;
int height = size.y;
int iWidth = bg.getWidth();
int iHeight = bg.getHeight();
for (int x = 0; x < width; x += iWidth) {
for (int y = 0; y < height; y += iHeight)
canvas.drawBitmap(bg, x, y, null);
}
loadWorld(FILENAME);
invalidate();
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity" >
<com.seanheiss.shovelshovel.DisplayMap.TileBackground
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/TileBackground" />
<ImageView
android:id="#+id/MapImage"
android:layout_width="fill_parent"
android:layout_height="fill_parent" />
</RelativeLayout>
By commenting one setContentView and not the other I can draw one piece, but I can't figure out how to draw both. I've heard of something called ViewFlipper, but am unsure if I should use that or not; I don't know how it works.
Thank you very much to anyone that can help me!
You should add your custom view (TileBackground) to your activity_main.xml layout file. That should allow it to be drawn properly when you use setContentView on activity_main. You'll probably want it as the first element under a RelativeLayout parent so that it gets drawn in the background.
In your case, you should have as your first element of the RelativeLayout:
<com.YOUR_PACKAGE.TileBackground
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="#+id/TileBackground" />
Related
I'm using mpchart to draw my charts.I wanted to increase the circle size of intersection point of highlighter and line dataset. How can I achieve this?
I read somewhere that we can add another dataset with highlighted point and increase its circle size. Is that really a good approach if my highlighter will be dragged back and forth and I'll have to update the new dataset very frequently?
When using the MpChart Library, the library contains a MarkerView class that helps us to insert the markers for displaying the selected value in the chart. We can use this MarkerView class to display any kind of view for the selected chart data.
So for the dot I created a new ChartMarker class and extended MarkerView class. Then in the constructor I passed the layout containing an image view with the dot as the src to the super.
public ChartMarker(Context context) {
//the super will take care of displaying the layout
super(context, R.layout.layout_dot);
}
Finally set the ChartMarker instance to the chart through chart.setMarkerView()
ChartMarker elevationMarker = new ChartMarker(getActivity());
elevationChart.setMarkerView(elevationMarker);
And for the layout_dot.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<ImageView
android:background="#drawable/dot"
android:layout_width="5dp"
android:layout_height="5dp" />
</LinearLayout>
I find ultimate solution.another question only can draw one point of one dataset in linechart,if I have two dataset like below,it will not draw two point。
Below code is my solution:
(it should edit the library source code,so pls import as module)
1、in LineChartRenderer class
private final Paint mHighlightPointStokePaint = new Paint();
private final Paint mHighlightPointInnerPaint = new Paint();
#Override
public void drawHighlighted(Canvas c, Highlight[] indices) {
LineData lineData = mChart.getLineData();
int entryIndex = -1;
for (Highlight high : indices) {
ILineDataSet set = lineData.getDataSetByIndex(high.getDataSetIndex());
if (set == null || !set.isHighlightEnabled())
continue;
Entry e = set.getEntryForXValue(high.getX(), high.getY());
if (!isInBoundsX(e, set))
continue;
entryIndex = set.getEntryIndex(e);
MPPointD pix = mChart.getTransformer(set.getAxisDependency()).getPixelForValues(e.getX(), e.getY() * mAnimator
.getPhaseY());
high.setDraw((float) pix.x, (float) pix.y);
// draw the lines
drawHighlightLines(c, (float) pix.x, (float) pix.y, set);
}
if (entryIndex < 0) {
return;
}
if (mChart instanceof BarLineChartBase) {
BarLineChartBase chart = (BarLineChartBase) this.mChart;
if (chart.isDrawHighlightPoint()) {
mHighlightPointInnerPaint.reset();
mHighlightPointInnerPaint.setAntiAlias(true);
mHighlightPointInnerPaint.setStyle(Paint.Style.FILL);
//交点外圈白环
mHighlightPointStokePaint.reset();
mHighlightPointStokePaint.setAntiAlias(true);
mHighlightPointStokePaint.setStyle(Paint.Style.STROKE);
mHighlightPointStokePaint.setStrokeWidth(chart.getHighLightPointStrokeWidth());
mHighlightPointStokePaint.setColor(Color.WHITE);
List<ILineDataSet> dataSets = lineData.getDataSets();
for (ILineDataSet set : dataSets) {
if (entryIndex < set.getEntryCount()) {
Entry e = set.getEntryForIndex(entryIndex);
MPPointD pix = mChart.getTransformer(set.getAxisDependency())
.getPixelForValues(e.getX(), e.getY() * mAnimator.getPhaseY());
drawHighlightPoint(c, (float) pix.x, (float) pix.y, chart, set);
}
}
}
}
}
private void drawHighlightPoint(Canvas c, float x, float y, BarLineChartBase chart, ILineDataSet set) {
//点内圆的颜色和图表线条一致,且将颜色的不透明度调满!
mHighlightPointInnerPaint.setColor(((255) << 24) | set.getColor());
//绘制内圆
c.drawCircle(x, y, chart.getHighLightPointInnerRadius(), mHighlightPointInnerPaint);
//绘制外圆
c.drawCircle(x, y, chart.getHighLightPointInnerRadius(), mHighlightPointStokePaint);
}
2、in BarLineChartBase class
/**
* flag that indicates if draw highlight point is enabled or not
*/
protected boolean isDrawHighlightPoint = false;
/**
* the highlight point inner radius (px)
*/
protected int mHighLightPointInnerRadius = 1;
/**
* the highlight point stroke width (px)
*/
protected int mHighLightPointStrokeWidth = 1;
public boolean isDrawHighlightPoint() {
return isDrawHighlightPoint;
}
public void setDrawHighlightPoint(boolean drawHighlightPoint) {
isDrawHighlightPoint = drawHighlightPoint;
}
public int getHighLightPointInnerRadius() {
return mHighLightPointInnerRadius;
}
public void setHighLightPointInnerRadius(int mHighLightPointStrokeWidth) {
this.mHighLightPointInnerRadius = mHighLightPointStrokeWidth;
}
public int getHighLightPointStrokeWidth() {
return mHighLightPointStrokeWidth;
}
public void setHighLightPointStrokeWidth(int mHighLightPointStrokeWidth) {
this.mHighLightPointStrokeWidth = mHighLightPointStrokeWidth;
}
3、apply to your chart
lineChart.setDrawHighlightPoint(true);
lineChart.setHighLightPointInnerRadius(Utils.dp2px(5, context));
lineChart.setHighLightPointStrokeWidth(Utils.dp2px(3, context));
Let me explain what I am doing first before I get into everything
basically I give the user an option to choose an image from the SD card, store the Uri of selected image in my database and have that as the avatar for the list item but the more list items with an avatar there are the slower the scrolling of the list is
I load the list with a Loader
#Override
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
return new CursorLoader(getActivity(),BowlersDB.CONTENT_URI,
new String[] {BowlersDB.ID,BowlersDB.FIRST_NAME,BowlersDB.LAST_NAME,BowlersDB.PHOTO_URI},null,null,BowlersDB.LAST_NAME + " COLLATE LOCALIZED ASC");
}
I have a custom adapter that adjusts the image size sets the textviews etc.
#Override
public void bindView(final View view,final Context context,final Cursor cursor){
final int id = cursor.getInt(0);;
final QuickContactBadge image = (QuickContactBadge)view.findViewById(R.id.quickContactBadge1);
image.setOnClickListener(new View.OnClickListener(){
#Override
public void onClick(View v) {
if(!fromGame){
bowlerID = id;
Intent i = new Intent(Intent.ACTION_PICK,android.provider.MediaStore.Images.Media.EXTERNAL_CONTENT_URI);
startActivityForResult(i,1);
}
}
});
String uri = cursor.getString(3);
if(uri != null){
InputStream input=null;
try {
input = getActivity().getContentResolver().openInputStream(Uri.parse(cursor.getString(3)));
BitmapFactory.Options options = new BitmapFactory.Options();
options.inJustDecodeBounds = false;
Bitmap og = BitmapFactory.decodeStream(input,null,options);
int height = options.outHeight;
int width = options.outWidth;
BitmapFactory.decodeResource(getResources(), R.drawable.ic_contact_picture, options);
int imageHeight = options.outHeight;
int imageWidth = options.outWidth;
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
float scaledHeight = ((float)imageHeight)/height;
float scaledWidth = ((float)imageWidth)/width;
Matrix matrix = new Matrix();
matrix.postScale(scaledWidth, scaledHeight);
final Bitmap resized = Bitmap.createBitmap(og, 0, 0, width, height, matrix, true);
try {
input.close();
} catch (IOException e) {
e.printStackTrace();
}
image.setImageBitmap(resized);
} catch (FileNotFoundException e) {
e.printStackTrace();
}
}else{
image.setImageResource(R.drawable.ic_contact_picture);
}
TextView first = (TextView)view.findViewById(R.id.bListTextView);
TextView last = (TextView)view.findViewById(R.id.bListTextView2);
first.setText(cursor.getString(1));
last.setText(cursor.getString(2));
}
}
Now I know its probably the sizing of the image that is causing it to be so slow but when I put that section of code in a separate thread and that had no effect but I thought a LoaderManager loads everything in the background anyway
here is my row xml
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:minHeight="60dp"
android:id="#+id/names_layout"
android:background="#drawable/list_item_state">
<QuickContactBadge
android:id="#+id/quickContactBadge1"
android:layout_width="70dp"
android:layout_height="70dp"
android:layout_alignParentLeft="true"
android:layout_alignParentTop="true"
android:src="#drawable/ic_contact_picture"
style="?android:attr/quickContactBadgeStyleWindowLarge" />
<TextView
android:id="#+id/bListTextView"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="#+id/quickContactBadge1"
android:background="#drawable/list_item_state"
android:paddingLeft="20dp"
android:paddingTop="2dp"
android:textAppearance="?android:attr/textAppearanceLarge"
android:textSize="20dp"
android:textColor="?android:attr/textColorPrimary" />
<TextView
android:id="#+id/bListTextView2"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:layout_toRightOf="#+id/quickContactBadge1"
android:layout_below="#+id/bListTextView"
android:paddingLeft="20dp"
android:background="#drawable/list_item_state"
android:textAppearance="?android:attr/textAppearanceMedium"
android:textSize="15dp"
android:textColor="?android:attr/textColorSecondary"
android:layout_alignBottom="#+id/quickContactBadge1"/>
</RelativeLayout>
the Quick Contact Badge holds the image and I have a default image set for if there is no image set.
So how can I fix this?
An example of what I am trying to do would be the google music app where the album list has all those album avatars and there is no problem scrolling, they appear on a as needed basis it seems but obviously its a bit different since the images are probably downloaded from the server
You can lazyLoad the images for the list view. here is a complete example:
http://codehenge.net/blog/2011/06/android-development-tutorial-asynchronous-lazy-loading-and-caching-of-listview-images/
You are streaming the image in the bindView thread, which generally is not a good idea. I usually do downloading and building bitmaps in an asyncTask - or rather, in a RoboAsyncTask. I pass the ImageView along with the image URL, so the image is set after the downloading or bitmapcreation is done, in the onSuccess() of the asynctask. What you see on the screen is images appearing shortly after the other content. You can also pass a placeholder resource to the async task, to display while the downloading is being done.
In your activity or fragment:
mediaManager.setImage(imageUrl, imageView, R.drawable.placeholder_image);
in MediaManager:
#Override
public void setImage(String imageUrl, ImageView imageView, int placeholderResource) {
new SetImageTask(context, imageUrl, imageView, placeholderResource).execute();
}
#Override
public Bitmap getImage(String imageUrl) throws IllegalStateException, IOException, SQLException {
// put your code to fetch image here....
}
In SetImageTask (extends RoboAsyncTask):
#Override
public void onPreExecute() {
imageView.setImageResource(placeholderResource);
}
#Override
public Bitmap call() throws Exception {
return mediaManager.getImage(imageUrl);
}
#Override
public void onSuccess(Bitmap bitmap) {
imageView.setImageBitmap(bitmap);
}
I'm building a real simple Android app and a lot is going wrong.
I can't even get a decent Try Catch Everything running. And since the machine I got is hugely underpowered I'm testing directly on my android device but that's not really working.
The application seems to crash after doing a basic action even using a generic try catch. What am I doing wrong here.
Why is the try catch not catching anything?
This is my Main.xml (a textview and another control are snipped out)
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
>
<ImageButton
android:id="#+id/ib"
android:layout_width="300dip"
android:layout_height="50dip"
android:text="Hello World, MyActivity"
android:scaleType="fitXY"
android:onClick="onButtonClicked"
/>
This is my simple code (and the Image isn't even showing)
public void onButtonClicked(View v) {
try {
String strFilePath = "/mnt/sdcard/somefile.jpg";
if (strFilePath.length() > 0) {
File file = new File(strFilePath);
if (file.exists()) {
ShowToast(strFilePath + "Bestaat");
ImageButton image = (ImageButton) findViewById(R.id.ib);
Bitmap bMap = BitmapFactory.decodeFile(strFilePath);
image.setImageBitmap(bMap);
ShowToast( "Done");
} else {
ShowToast(strFilePath + "Bestaat NIET");
}
} else {
ShowToast(strFilePath + "strFilePath.length() =0");
}
} catch (Exception e) {
HandleError(e);
}
}
Solution
The files where over 3Mb in size. The ImageButton won't show pictures that 'big' and simply do nothing.
The application probably threw some random out of memory exceptions loading the images taking down the entire app.
Reading a logcat was enough to debug this 'problem'
Some code that does work (kindly borrowed from other SO questions)
ImageButton image = (ImageButton) findViewById(R.id.ib);
Bitmap bMap = BitmapFactory.decodeFile(strFilePath);
Bitmap bSized = getResizedBitmap(bMap,150,150);
image.setImageBitmap(bSized);
And
public Bitmap getResizedBitmap(Bitmap bm, int newHeight, int newWidth)
{
int width = bm.getWidth();
int height = bm.getHeight();
float scaleWidth = ((float) newWidth) / width;
float scaleHeight = ((float) newHeight) / height;
// create a matrix for the manipulation
Matrix matrix = new Matrix();
// resize the bit map
matrix.postScale(scaleWidth, scaleHeight);
// recreate the new Bitmap
Bitmap resizedBitmap = Bitmap.createBitmap(bm, 0, 0, width, height, matrix, false);
return resizedBitmap;
}
Either you don't have an ImageButton with that id, or the image you are trying to load is to big to fit in the reduced application memory.
I have tested your code snippets..
First of all, the ImageButton will not show the android:text part because that attribute belongs to Button..
With just the LinearLayout and the ImageButton in main.xml in the res/layout folder and this code it works fine:
public class Main extends Activity {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
}
public void onButtonClicked(View v) {
try {
String strFilePath = "/mnt/sdcard/somefile.png";
if (strFilePath.length() > 0) {
File file = new File(strFilePath);
if (file.exists()) {
//ShowToast(strFilePath + "Bestaat");
ImageButton image = (ImageButton) findViewById(R.id.ib);
Bitmap bMap = BitmapFactory.decodeFile(strFilePath);
image.setImageBitmap(bMap);
//ShowToast( "Done");
} else {
//ShowToast(strFilePath + "Bestaat NIET");
}
} else {
//ShowToast(strFilePath + "strFilePath.length() =0");
}
} catch (Exception e) {
//HandleError(e);
e.printStackTrace();
}
}
}
So either the file is to big as K-Ballo suggested or something is wrong with your ShowToast or HandleError methods.
I have a xml file :
<?xml version="1.0" encoding="utf-8"?>
<bitmap xmlns:android="http://schemas.android.com/apk/res/android"
android:src="#drawable/header"
android:tileMode="repeat" />
I have a header and I would like to repeat my drawable only in X and stretch it in Y. How could I do that in xml.
first try :
I remove my xml and I've done that at the beginning of my activity:
BitmapDrawable bp =(BitmapDrawable)getResources().getDrawable(R.drawable.header);
bp.setTileModeX(TileMode.REPEAT);
LinearLayout layout = (LinearLayout)findViewById(R.id.headerRedLayout);
layout.setBackgroundDrawable(bp);
It works great but I would like that the repeat starts at the bottom of the layout
In the onDraw() method do this
keep in mind R.drawable.bg_tile is your image
protected void onDraw (Canvas canvas) {
bgTile = BitmapFactory.decodeResource(context.getResources(), R.drawable.bg_tile);
float left = 0;
float top = 0;
float bgTileWidth = bgTile.getWidth();
int screenWidth = canvas.getWidth(); //Not sure of this
int screenHeight = canvas.getHeight(); //Not sure of this too
while (left < screenWidth) {
canvas.drawBitmap(
bgTile,
null,
new Rect(left,top,left+bgTileWidth,screenHeight),
null
);
left += bgTileWidth;
}
}
I wrote code to draw on a view. After it is done, how can I get the resulting image from the view. For example, in the code below, I want to get the the drawable (Image) from mCustomDrawableView. How can I do that? Thanks.
public class HelloTestGraph extends Activity {
/** Called when the activity is first created. */
// #Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout lo = (LinearLayout) findViewById(R.id.top_view);
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
CustomDrawableView mCustomDrawableView = new CustomDrawableView(this);
mCustomDrawableView.setLayoutParams(param);
lo.addView(mCustomDrawableView);
}
public class CustomDrawableView extends View {
private ShapeDrawable mDrawable;
private Drawable mPic;
public CustomDrawableView(Context context) {
super(context);
int x = 10;
int y = 10;
int width = 300;
int height = 50;
mDrawable = new ShapeDrawable(new OvalShape());
mDrawable.getPaint().setColor(0xff74AC23);
mDrawable.setBounds(x, y, x + width, y + height);
mPic = getResources().getDrawable(R.drawable.example_picture);
mPic.setBounds(x, y + 100, x + width, y + height+100);
}
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
mPic.draw(canvas);
}
}
}
This is a little convoluted, but should get you there.
Step 1: Create a Muteable Bitmap of the size you want and stash it aside. It could be the size of the device's screen or the size of your largest view (depending on what you want to do with it later) Save that bitmap pointer aside as something like myBitmap
Step 2: Create a canvas with the aforementioned bitmap. "Canvas myCanvas = new Canvas(myBitmap);"
Step 3: In your onDraw() method, draw your views both to the passed in "canvas" object, and to your own custom one.
protected void onDraw(Canvas canvas) {
mDrawable.draw(canvas);
mPic.draw(canvas);
mDrawable.draw(myCanvas);
mPic.draw(myCanvas);
}
Step 4: Your original bitmap should now contain the fully rendered version of ONLY your view.
I'm not sure if this is exactly what you're looking for, but it will give you a bitmap (which you can convert into an image) of the contents of your view.
From inside your custom class, you'd specify getters and setters if you wanted to access them from outside the class.
public Drawable getDrawable() { return mDrawable; }
Then from outside the class (as in your activity), you can call the getDrawable() method on the view once it's instantiated.
Drawable drawable = mCustomDrawableView.getDrawable();