Blackberry support multiple resolutions [duplicate] - user-interface

This question already has answers here:
Supporting multiple screens - Blackberry
(2 answers)
Closed 8 years ago.
I need to design the UI for a blackberry app. This app should support multiple blackberry resolutions.
One way would be to check the screen_width and screen_height every time, and accordingly fetch images from the res folder. Is there any other more efficient, or a better method to do this? I will also need to do the same for font sizes, of text, according to screen size.
Please help me know the standard method to support multiple BB resolutions

You can try, what I have tried in my applications without any issues so far.
Step 1:
Create a separate package like com.your_app_name.uiconfig which will
contain an abstract class say ModelConfig and different classes for
different resolutions like class BB83xxConfig for resolution 320x240
(width x height), class BB95xxConfig for resolution 360 x 480 (width x
height).
Step 2:
ModelConfig class will provide the concrete implementation of the
methods that will be common to all irrespective of the screen
resolutions and the declaration of abstract methods whose concrete
implementation will be provided in the respective classes based on the
screen resolution.
Step 3: Make each and every class, that is implemented for particular resolution extend ModelConfig and provide concrete
implementation of methods as per requirement.
Step 4: Use singleton pattern to get the instance of ModelConfig, so that it is intantiated only once and that instance is used
throughout.
ModelConfig.java (Just a sample)
public abstract class ModelConfig {
private static ModelConfig modelConfig = null;
public static ModelConfig getConfig() {
if (modelConfig == null) {
if (DeviceInfo.getDeviceName().startsWith("83")) {
modelConfig = new BB83xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("85")) {
// 85xx also has 360 x 240 same as 83xx device
modelConfig = new BB83xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("89")) {
modelConfig = new BB89xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("90")) {
modelConfig = new BB90xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("95")) {
modelConfig = new BB95xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("96")) {
modelConfig = new BB96xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("97")) {
modelConfig = new BB97xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("99")) {
modelConfig = new BB99xxConfig();
} else if (DeviceInfo.getDeviceName().startsWith("98")) {
// 9800 also has 360 x 480 same as 95xx device
modelConfig = new BB95xxConfig();
}else {
modelConfig = new DefaultConfig();
}
}
return modelConfig;
}
// Font height for the default font used for the application.
public abstract int getApplicationFontHeight();
// Font height for the header label font.
public abstract int getHeaderLabelFontHeight();
// Height for the coloured background of Header.
public abstract int getHeaderBarHeight();
// Height for the individual row in the list.
public abstract int getCustomListRowHeight();
public abstract int getStandardButtonWidth();
public abstract int getStandardLabelWidth();
public abstract int getTitleFontHeight();
// get Background colour for Header.
public int getHeaderBackgroundColor() {
return 0x26406D;
}
// get Bitmap showing Right Arrow.
public Bitmap getBitmapRightArrow() {
return Bitmap.getBitmapResource("right_arrow.png");
}
// get Bitmap rounded black border for editfield.
public Bitmap getBitmapRoundedBorderEdit(){
return Bitmap.getBitmapResource("rounded_border_black.png");
}
// get Bitmap rounded gray border and white background.
public Bitmap getBtmpRoundedBorderBgrnd(){
return Bitmap.getBitmapResource("rounded_border_grey.png");
}
// get Bitmap rounded gray border and white background.
public Bitmap getBtmpTransparentBgrnd(){
return Bitmap.getBitmapResource("img_transparent_background.png");
}
// get Bitmap showing down Arrow.
public Bitmap getBitmapDownArrow(){
return Bitmap.getBitmapResource("down_arrow.png");
}
}
BB95xxConfig.java (just a sample)
/*
* Common resolution 360*480 pixels (width x height)
*/
public class BB95xxConfig extends ModelConfig {
// Font height for the default font used for the application.
// returns Desired height in pixels.
public int getApplicationFontHeight() {
return 18;
}
// Font height for the header label font.
// returns Desired height in pixels.
public int getHeaderLabelFontHeight() {
return 20;
}
// returns Desired height in pixels for the header background.
public int getHeaderBarHeight() {
return Display.getHeight() / 10;
}
public int getCustomListRowHeight() {
return 50;
}
public int getStandardButtonWidth() {
return 108;
}
public int getStandardLabelWidth() {
return 150;
}
public int getTitleFontHeight() {
return 11;
}
}

Related

Android - How to make google Maps display a polyline that animates sequenctial flashing dots

I am searching for a way to animate the dots between two markers on a google map in android device.
So what i want in the end is the following line between the two images:
and it would be used like this typical google polyline implementation:
lets say there is a point A and a Point B. if im directing the user to point B, then the line animates to from point A to point B so the user knows to walk in this direction.
to achieve this i thought i could get the points out of the polyLine and remove them and add them back
rapidily. so lets say i had 5 points in the polyLine, i would remove position 1 , then put it back, then remove position 2, and put it back, to simulate this animation.
but it does not work . once hte polyline is set it seems i cannot alter it. you have any suggestions ?
val dotPattern = Arrays.asList(Dot(), Gap(convertDpToPixel(7).toFloat()))
val polyLineOptions: PolylineOptions = PolylineOptions()
.add(usersLocation)
.add(users_destination)
.pattern(dotPattern)
.width(convertDpToPixel(6).toFloat())
dottedPolyLine = googleMap.addPolyline(polyLineOptions)
dottedPolyLine?.points?.removeAt(1) // here as a test if my idea i try removing a point but it looks like a point here means current location or destination so there always 2. i thought a point would be one of the dots.
You can use MapView-based custom view View Canvas animationlike in this answer:
This approach requires
MapView-based
custom
view,
that implements:
drawing over the MapView canvas;
customizing line styles (circles instead of a simple line);
binding path to Lat/Lon coordinates of map
performing animation.
Drawing over the MapView needs to override dispatchDraw().
Customizing line styles needs
setPathEffect()
method of
Paint
class that allows to create create path for "circle stamp" (in
pixels), which will repeated every "advance" (in pixels too),
something like that:
mCircleStampPath = new Path(); mCircleStampPath.addCircle(0,0,
CIRCLE_RADIUS, Path.Direction.CCW); mCircleStampPath.close();
For binding path on screen to Lat/Lon coordinates
Projection.toScreenLocation()
needed, that requires
GoogleMap
object so custom view should implements OnMapReadyCallback for
receive it. For continuous animation
postInvalidateDelayed()
can be used.
but not draw path directly from point A to point B, but from point A to point C that animated from A to B. To get current position of point C you can use SphericalUtil.interpolate() from Google Maps Android API Utility Library. Something like that:
public class EnhancedMapView extends MapView implements OnMapReadyCallback {
private static final float CIRCLE_RADIUS = 10;
private static final float CIRCLE_ADVANCE = 3.5f * CIRCLE_RADIUS; // spacing between each circle stamp
private static final int FRAMES_PER_SECOND = 30;
private static final int ANIMATION_DURATION = 10000;
private OnMapReadyCallback mMapReadyCallback;
private GoogleMap mGoogleMap;
private LatLng mPointA;
private LatLng mPointB;
private LatLng mPointC;
private float mCirclePhase = 0; // amount to offset before the first circle is stamped
private Path mCircleStampPath;
private Paint mPaintLine;
private final Path mPathFromAtoC = new Path();
private long mStartTime;
private long mElapsedTime;
public EnhancedMapView(#NonNull Context context) {
super(context);
init();
}
public EnhancedMapView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
init();
}
public EnhancedMapView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init();
}
public EnhancedMapView(#NonNull Context context, #Nullable GoogleMapOptions options) {
super(context, options);
init();
}
#Override
public void dispatchDraw(Canvas canvas) {
super.dispatchDraw(canvas);
canvas.save();
drawLineFomAtoB(canvas);
canvas.restore();
// perform one shot animation
mElapsedTime = System.currentTimeMillis() - mStartTime;
if (mElapsedTime < ANIMATION_DURATION) {
postInvalidateDelayed(1000 / FRAMES_PER_SECOND);
}
}
private void drawLineFomAtoB(Canvas canvas) {
if (mGoogleMap == null || mPointA == null || mPointB == null) {
return;
}
// interpolate current position
mPointC = SphericalUtil.interpolate(mPointA, mPointB, (float) mElapsedTime / (float)ANIMATION_DURATION);
final Projection mapProjection = mGoogleMap.getProjection();
final Point pointA = mapProjection.toScreenLocation(mPointA);
final Point pointC = mapProjection.toScreenLocation(mPointC);
mPathFromAtoC.rewind();
mPathFromAtoC.moveTo(pointC.x, pointC.y);
mPathFromAtoC.lineTo(pointA.x, pointA.y);
// change phase for circles shift
mCirclePhase = (mCirclePhase < CIRCLE_ADVANCE)
? mCirclePhase + 1.0f
: 0;
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
canvas.drawPath(mPathFromAtoC, mPaintLine);
}
private void init() {
setWillNotDraw(false);
mCircleStampPath = new Path();
mCircleStampPath.addCircle(0,0, CIRCLE_RADIUS, Path.Direction.CCW);
mCircleStampPath.close();
mPaintLine = new Paint();
mPaintLine.setColor(Color.BLACK);
mPaintLine.setStrokeWidth(1);
mPaintLine.setStyle(Paint.Style.STROKE);
mPaintLine.setPathEffect(new PathDashPathEffect(mCircleStampPath, CIRCLE_ADVANCE, mCirclePhase, PathDashPathEffect.Style.ROTATE));
// start animation
mStartTime = System.currentTimeMillis();
postInvalidate();
}
#Override
public void getMapAsync(OnMapReadyCallback callback) {
mMapReadyCallback = callback;
super.getMapAsync(this);
}
#Override
public void onMapReady(GoogleMap googleMap) {
mGoogleMap = googleMap;
mGoogleMap.setOnCameraMoveListener(new GoogleMap.OnCameraMoveListener() {
#Override
public void onCameraMove() {
invalidate();
}
});
if (mMapReadyCallback != null) {
mMapReadyCallback.onMapReady(googleMap);
}
}
public void setPoints(LatLng pointA, LatLng pointB) {
mPointA = pointA;
mPointB = pointB;
}
}
NB! This is just idea, not full tested code.

How to get DPI device to PCL in Xamarin. Forms?

I need to get DPI device in my Xamarin class PCL. I do not want to use Xamarin.Essentials. Can I do this using Native interfaces, if its possible, how can I do it?
in your pcl create a new interface called IDisplayInfo:
public interface IDisplayInfo
{
int GetDisplayWidth();
int GetDisplayHeight();
int GetDisplayDpi();
}
In your android implementation, add a new class:
[assembly: Dependency(typeof(DisplayInfo))]
namespace YourAppNamespace.Droid
{
public class DisplayInfo : IDisplayInfo
{
public int GetDisplayWidth()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.WidthPixels;
}
public int GetDisplayHeight()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.HeightPixels;
}
public int GetDisplayDpi()
{
return (int)Android.App.Application.Context.Resources.DisplayMetrics.DensityDpi;
}
}
}
and in the iOS implementation, add the same class:
[assembly: Dependency(typeof(DisplayInfo))]
namespace YourNamespace.iOS
{
public class DisplayInfo : IDisplayInfo
{
public int GetDisplayWidth()
{
return (int)UIScreen.MainScreen.Bounds.Width;
}
public int GetDisplayHeight()
{
return (int)UIScreen.MainScreen.Bounds.Height;
}
public int GetDisplayDpi()
{
return (int)(int)UIScreen.MainScreen.Scale;
}
}
}
Now in your shared code, you can call
int dpi = DependencyService.Get<IDisplayInfo>().GetDisplayDpi();
and should be good to go. Note that i also added methods for getting screen width and height, basically because i already had them in my code and since you are probably going to need them sooner or later anyways.
Currently Device Display Information available via official Xamarin.Essentials nuget package, see:
https://learn.microsoft.com/en-us/xamarin/essentials/device-display
// Get Metrics
var mainDisplayInfo = DeviceDisplay.MainDisplayInfo;
// Orientation (Landscape, Portrait, Square, Unknown)
var orientation = mainDisplayInfo.Orientation;
// Rotation (0, 90, 180, 270)
var rotation = mainDisplayInfo.Rotation;
// Width (in pixels)
var width = mainDisplayInfo.Width;
// Height (in pixels)
var height = mainDisplayInfo.Height;
// Screen density
var density = mainDisplayInfo.Density;
I think it will help you. Here you have it described
enter link description here
I have a static class Core to store some shared stuff defined the shared code.
On app start it's receiving values for later use everywhere:
Android MainActivity OnCreate:
Core.IsAndroid = true;
Core.DisplayDensity = Resources.DisplayMetrics.Density;
iOS AppDelegate FinishedLaunching:
Core.IsIOS = true;
Core.DisplayDensity = (float)(UIScreen.MainScreen.NativeBounds.Width / UIScreen.MainScreen.Bounds.Width);

Position and rotate animations in Libgdx

I have 20 spites, I want them to be animated when a button is clicked.
Two types of animations 1) Position 2) Rotation.
Is there a recommended way to do this? Only way I can think of is recursively call setposition and angle with a delta value on Render method till the desired position and angle are reached.
When you have a start state and an end state, and you want to fill in the middle states, this is known as 'tweening (from inbetween). It comes from cartoon animation, but has come to be used more generally.
LibGDX makes use of Universal Tween Engine. You can start your journey to animating anything you want here. But, to give a bit more detail on how it works, here is an example from some of my own stuff. A similar usecase with regards to a sprite, but I have my sprites wrapped in a more generic class, a JJRenderNode. Here is how I make my class open to being tweened.
First you need a TweenAccessor for the class you want to tween.
public class RenderNodeTweenAccessor implements TweenAccessor<JJRenderNode> {
public static final int WIDTH = 1;
public static final int HEIGHT = 2;
public static final int WIDTH_HEIGHT = 3;
public static final int ALPHA = 4;
public static final int ALPHA_WIDTH_HEIGHT=5;
#Override
public int getValues(JJRenderNode target, int tweenType, float[] returnValues) {
switch (tweenType) {
case WIDTH:
returnValues[0] = target.getWidth();
return 1;
case HEIGHT:
returnValues[0] = target.getHeight();
return 1;
case WIDTH_HEIGHT:
returnValues[0] = target.getWidth();
returnValues[1] = target.getHeight();
return 2;
case ALPHA:
returnValues[0] = target.getColour().a;
return 1;
case ALPHA_WIDTH_HEIGHT:
returnValues[0] = target.getColour().a;
returnValues[1] = target.getWidth();
returnValues[2] = target.getHeight();
return 3;
default:
assert false;
return -1;
}
}
#Override
public void setValues(JJRenderNode target, int tweenType, float[] newValues) {
switch (tweenType) {
case WIDTH:
target.setWidth(newValues[0]);
break;
case HEIGHT:
target.setHeight(newValues[0]);
break;
case WIDTH_HEIGHT:
target.setWidth(newValues[0]);
target.setHeight(newValues[1]);
break;
case ALPHA:
target.getColour().a=newValues[0];
break;
case ALPHA_WIDTH_HEIGHT:
target.getColour().a=newValues[0];
target.setWidth(newValues[1]);
target.setHeight(newValues[2]);
default:
break;
}
}
}
The constant ints and the 'tweenType' in each of the get and set methods let you tween more than one combination of fields. In this case I have different combinations of width, height and alpha values for my JJRenderNode.
You have to register this TweenAccessor as follows:
Tween.registerAccessor(JJRenderNode.class, new RenderNodeTweenAccessor());
And then you are free to tween your class, for example:
Timeline.createSequence()
.push(Tween.set(node, RenderNodeTweenAccessor.WIDTH_HEIGHT).target(START_WIDTH, START_WIDTH))
.push(Tween.to(node, RenderNodeTweenAccessor.WIDTH_HEIGHT, 0.4f).target(PuzzleBlockCore.MAX_RENDER_WIDTH, PuzzleBlockCore.MAX_RENDER_WIDTH))
.start(JJ.tweenManager);
PS. You also need an instance of a TweenManger, and this needs to be updated with delta for each gameloop. I have a 'singleton' global instance that I use everywhere (JJ.TweenManager).
You might as well use spine 2d for animation. It costs, but it is worth it. For $60 I think, you get full libgdx support + bone rigging and animation.
http://esotericsoftware.com/
If you do want to animate with only libgdx however, you can create a list with all your sprite animations frames, loop through, and switch sprite texture to next frame in the animation.
private void render() {
sprite.set(aninationframes.get(currentFrame)
currentFrame = currentFrame + 1}
Though, you may want to add a delay per frame.
If(current time - time > some value) {
sprite.set(animationframes.get(currrntFrame)
currentFrame = currentFrame + 1
time = get current time here
}

LibGDX / Box2d - only one rectangle is being rendered by debugrenderer

I'm revisiting LibGDX game programming and I am unfortunately having to re-learn stuff I used to know.
I'm currently using Tiled Map Editor to make a very simple Donkey Kong style level. I have around 20 rectangles in total for the level.
I've created a box2d world in my main GameScreen class and have a for loop to get the rectangle objects into the world and debugrenderer.
My problem is that only the bottom (and first) rectangle I drew is showing up. I have checked the scale, also I put a println() which tells me the object information has been parsed with all the rectangles info showing correct (ie. the rectangles x,y,w,h values) but as I say, only one rectangle shows up on the debugrenderer.
I've just got back into programming after around 6month break and so I'm hoping i've missed something simple. The same code in my old projects still works fine as I've tested some.
Here is my code, any help is massively appreciated. Thanks
public class GameScreen implements Screen {
SpriteBatch spriteBatch;
OrthographicCamera cam;
Viewport v;
TmxMapLoader mapLoader;
TiledMap map;
OrthogonalTiledMapRenderer mapRenderer;
World world;
Box2DDebugRenderer b2dr;
float mapScale = 10f/140f;
public GameScreen(){
spriteBatch = new SpriteBatch();
cam = new OrthographicCamera();
v = new FitViewport(Constants.V_WIDTH, Constants.V_HEIGHT, cam);
cam.setToOrtho(false, v.getWorldWidth(), v.getWorldHeight());
mapLoader = new TmxMapLoader();
map = mapLoader.load("level1.tmx");
mapRenderer = new OrthogonalTiledMapRenderer(map, mapScale);
world = new World(new Vector2(0,-9.8f), true);
b2dr = new Box2DDebugRenderer();
// box2d local variables
BodyDef bdef = new BodyDef();
PolygonShape shape = new PolygonShape();
FixtureDef fdef = new FixtureDef();
Body body;
// create platform object rectangles
for (MapObject object : map.getLayers().get(2).getObjects().getByType(RectangleMapObject.class)){
Rectangle rect = ((RectangleMapObject)object).getRectangle();
bdef.type = BodyDef.BodyType.StaticBody;
bdef.position.set(rect.getX() + rect.getWidth() / 2 * mapScale, rect.y + rect.getHeight() / 2 * mapScale);
body = world.createBody(bdef);
shape.setAsBox(rect.getWidth() / 2 * mapScale, rect.getHeight() / 2 * mapScale);
fdef.shape = shape;
body.createFixture(fdef);
}
}
#Override
public void show() {
}
#Override
public void render(float delta) {
update(delta);
clearScreen();
draw();
}
public void update(float dt){
mapRenderer.setView(cam);
}
public void clearScreen(){
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
}
public void draw(){
spriteBatch.setProjectionMatrix(cam.combined);
mapRenderer.render();
b2dr.render(world, cam.combined);
spriteBatch.begin();
spriteBatch.end();
}
#Override
public void resize(int width, int height) {
v.update(width, height);
}
#Override
public void pause() {
}
#Override
public void resume() {
}
#Override
public void hide() {
}
#Override
public void dispose() {
spriteBatch.dispose();
}
}
Sorry for wasting time here. I have fixed this.
It was just that I hadnt applied the scale of the map also to the x,y of the rectangles. So i change one line like so, and now it works:
bdef.position.set(rect.getX() * mapScale + rect.getWidth() / 2 * mapScale, rect.y * mapScale + rect.getHeight() / 2 * mapScale);

Loading Images from sd card to grid view causes bitmap exceeds VM budget

In my Application im loading images from sd card almost 40 to 50 images in grid view for this i created adapter in which constructor loads images from sd card to global variable of array list of bitmaps with in get view im returning bitmap from array list the problem is from this activity user will move to other activity where he will delete image after deletion user will come back to grid activity and have to load the adapter again this creates "bitmap exceeds vm budget". so i don't know is this way to load images from sd card is there any better approach for that any libraries available for loading images from sd card with out memory leak
public class PicAdapter extends BaseAdapter {
int defaultItemBackground;
private Context galleryContext;
Bitmap placeholder;
public PicAdapter(Context c) {
// instantiate context
galleryContext = c;
// create bitmap array
bitmaplist=new ArrayList<Bitmap>();
GlobalData.imageBitmaps = new WeakReference<ArrayList<Bitmap>>(bitmaplist);
imageDescription = new ArrayList<String>();
imagetitle = new ArrayList<String>();
picturesCursor.moveToFirst();
int i = 0;
for (i = 0; i < picturesCursor.getCount(); i++) {
String imagepath = picturesCursor.getString(picturesCursor
.getColumnIndex("img"));
File cacheimage=new File(imagepath);
if(!cacheimage.exists())
{
dBopenHelper.deleteHappyMoments(imagepath);
}
else
{
Bitmap bitmap =
ViewUtils.decodeSampledBitmapFromResource(imagepath,
AppConstants.FRAME_WIDTH,
AppConstants.FRAME_HEIGHT);
ViewUtils.recycleBitmapFrame();
GlobalData.imageBitmaps.get().add(bitmap);
imageDescription.add(picturesCursor.getString(picturesCursor
.getColumnIndex("image_description")));
imagetitle.add(picturesCursor.getString(picturesCursor
.getColumnIndex("image_title")));
picturesCursor.moveToNext();
}
}
if (i == picturesCursor.getCount()) {
Bitmap bitmap = (Bitmap) BitmapFactory.decodeResource(getResources(), R.drawable.add_new);
GlobalData.imageBitmaps.get().add(bitmap);
imageDescription.add(
"Click Add to new Pictures..............");
}
// get the styling attributes - use default Andorid system resources
}
// BaseAdapter methods
// return number of data items i.e. bitmap images
public int getCount() {
return bitmaplist.size();
}
// return item at specified position
public Object getItem(int position) {
return position;
}
// return item ID at specified position
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent) {
if (convertView == null) {
convertView = (ImageView) getLayoutInflater().inflate(
R.layout.item_grid_image, null);
convertView.setLayoutParams(new GridView.LayoutParams(
AppConstants.FRAME_WIDTH, AppConstants.FRAME_HEIGHT));
}
galleryImageView = (ImageView) convertView;
galleryImageView.setImageBitmap(GlobalData.imageBitmaps.get().get(position));
public void addPic(Bitmap newPic) {
// set at currently selected index
GlobalData.imageBitmaps.get().add(currentPic, newPic);
}
// return bitmap at specified position for larger display
public Bitmap getPic(int posn) {
// return bitmap at posn index
return GlobalData.imageBitmaps.get().get(posn);
}
}
sample code helps me alot
thanks in advance
If your images have high dimension- you need to display them one by one using some kind of queue.
Make sure that you decode them correctly.

Resources