I've been a lurker on your forums for some time now, and they have helped me enormously on a variety of issues I've had, so thanks! :D
I'm trying to create my first app for android and it's a card game named shithead that my friends and I used to play often.
I've decided to use a RecyclerView to display your hand. I need to be able to dynamically add buttons (with card images) to the display at runtime. From what I can tell, I need an adapter for this.
Using the handy guide at "https:// guides.codepath.com/android/using-the-recyclerview" and attempting to modify it for my own purposes I've come very close to a test run of making this work. When I run the program on an emulator in Android Studio, it gives me the following display:
images displayed as grey rectangles
I feel like I've got to be really close, and I'm simply missing some crucial syntax for working with android or android studio.
In my Card object I build a String idText that correlates to the card images I have saved in my project's mipmap-hdpi, mipmap-xhdpi etc. folders (mipmap-hdpi shown below)
mipmap-hdpi folder in Android Studio
public Card(int suitInput, int rankInput)
{
suit = suitInput;
rank = rankInput;
faceUp = false;
text = RankString[rank] + " of " + SuitString[suit];
idText = "i_" + RankString[rank] + "_of_" + SuitString[suit];
}
I also have a function getImageId in my Card Class:
public static int getImageId(Context context) {
return context.getResources().getIdentifier("drawable/#+id/" + idText, null, context.getPackageName());
}
my onBindViewHolder method in my CardAdapter is below:
#Override
public void onBindViewHolder(CardAdapter.ViewHolder viewHolder, int position)
{
//get the data model based on position
Card card = mCards.get(position);
//Set item views baased on views and data model
ImageButton imageButton = viewHolder.cardButton;
imageButton.setImageResource(card.getImageId(mContext));
TextView textView = viewHolder.cardText;
textView.setText(card.text);
}
my MainActivity class does very little as of yet. It initializes one player, me, and a Deck of Card objects. It then gives me 6 cards off the top of the unshuffled deck, AKA 2 - 7 of diamonds. It then initializes the CardAdapter.
public class MainActivity extends AppCompatActivity {
Player me;
Deck deck;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.testdisplay);
//lookup the recyclerview in activity layout
RecyclerView rvCards = (RecyclerView) findViewById(R.id.rvCards);
me = new Player("Dr_StrangeKill");
deck = new Deck();
me.hand.add(deck.getCards().remove(0));
me.hand.add(deck.getCards().remove(0));
me.hand.add(deck.getCards().remove(0));
me.hand.add(deck.getCards().remove(0));
me.hand.add(deck.getCards().remove(0));
me.hand.add(deck.getCards().remove(0));
//create adapter passing in sample user data
CardAdapter adapter = new CardAdapter(this, me.hand);
//Attach the adapter to the recyclerView to populate items
rvCards.setAdapter(adapter);
//Set layout manager to position the items
rvCards.setLayoutManager(new LinearLayoutManager(this));
}
The Deck, Player, and Card objects all appear to be working as intended insofar as the values of the code are concerned, as the resultant display correctly shows that 'Dr_StrangeKill' has received 2 - 7 of Diamonds, but doesn't show the card images themselves! This is my first time working with images in any IDE (eclipse, visual studio, android studio), and I feel like i'm very close but off in some small but crucial way. Any help would be greatly appreciated!
I suggest you put your images in a drawable folder because mipmap folder is for launcher icons, if you want to support different screen densities, here's a link that shows you how to create a drawable folder for each screen density, after that you should get your image identifier like this:
context.getResources().getIdentifier(idText, "drawable", context.getPackageName());
It looks like you're trying to get the identifier of the image resource by name. In that case you could try:
return context.getResources().getIdentifier(idText, "mipmap", context.getPackageName());
But doing that is not recommended. See docs for getIdentifier()
https://developer.android.com/reference/android/content/res/Resources.html#getIdentifier(java.lang.String, java.lang.String, java.lang.String)
You could just add the id (an int) to your card object and instantiate like new Card(R.mipmap.hearts_2,2,"hearts") or however you're instantiating (seems like you're using public fields and no constructor) and grab that id in your adapter to set on the imageview.
Related
I have an xml file called activity_collage.xml with 2 street view fragments - I would like both fragments to display the street view of a given location - So a total of 2 street views on the screen
Here's my code:
public class Collage extends ActionBarActivity implements OnStreetViewPanoramaReadyCallback {
StreetViewPanoramaFragment topLeft, topRight;
static final LatLng posOne = new LatLng(43.771925, -79.512460);
static final LatLng posTwo = new LatLng(43.790634, -79.193632);
Here's where I initialize my 2 StreetViewFragment objects in my onCreate() method
topLeft =
(StreetViewPanoramaFragment) getFragmentManager()
.findFragmentById(R.id.picTL);
topLeft.getStreetViewPanoramaAsync(this);
topRight =
(StreetViewPanoramaFragment) getFragmentManager()
.findFragmentById(R.id.picTR);
Here's the overridden method from the OnStreetViewPanoramaReadyCallback interface ...
#Override
public void onStreetViewPanoramaReady(StreetViewPanorama panorama) {
panorama.setPosition(posOne);
}
But how do I set the street view for topRight?
According to http://code.google.com/p/gmaps-api-issues/issues/detail?id=6953, multiple StreetViewPanorama Objects are not supported. In my experience, no explicit errors occur, but the second StreetViewPanorama will remain blank.
Frustratingly, I don't think the documentation was updated like the above thread indicates it should have been.
I have the same problem with my fragment XML containing 2 fragments : map fragment, and StreetViewPanoramaFragment. StreetView stays blank. I managed to use it with a simple view instead of fragment.
With Kotlin it gives :
val myFrag=getView()!!.findViewById<StreetViewPanoramaView>(R.id.street_view_panorama)
myFrag.onCreate(savedInstanceState);
myFrag.getStreetViewPanoramaAsync(OnStreetViewPanoramaReadyCallback { panorama ->
panorama.setPosition(LatLng(55.758818, 37.620587))
svPano = panorama
})
I recently started developing for android and now im stuck! I created a listview but the standard colour is black, now i want to be able to show the text in whatever colour i want. This is the activity.
public class DisplayMalePage extends ActionBarActivity {
String[] maleArray = { "a","b","c"};
private ListView maleListView;
private ArrayAdapter maleArrayAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_display_male_page);
maleListView = (ListView) findViewById(R.id.maleList);
maleArrayAdapter = new ArrayAdapter(this, android.R.layout.simple_list_item_1, maleArray);
maleListView.setAdapter(maleArrayAdapter);
}
But this (i think due to simple_list_item_1) gives me a black colour. Also i would like the input of my array to be strings so it wil be easier to change language.
Eventually i would like to have a list with 2 top texts, a dividing bar and then the rest of the list (they will all be clickable).
I hope someone understands what i mean haha.
You cannot change any part of the listviews layout using the default ArrayAdapter. You need to define your own CustomArrayAdapter.
http://www.vogella.com/tutorials/AndroidListView/article.html#adapterown
This link is a very useful guide on how to do that.
Create your own layout which you will use in your list item. Make sure it contains a Textview with id text1. Something like this:
layout/my_list_item.xml
<TextView
android:id-"#+id/text1"
android:textColor="#android:color/white"
...... />
Then use this layout in your ArrayAdapter intialization instead of android.R.layout.simple_list_item_1.
maleArrayAdapter = new ArrayAdapter(this, R.layout.my_list_item, maleArray);
Note: If you want something more complex other than showing a simple text, you should use custom ArrayAdapter, as #user3567040 have pointed out.
I'm using Android Eclipse while working on a project where the user can save and upload notes with images.
I have a fragment which holds a textview and some thumbnail images. The user can add additional images by using the camera and they can remove images by viewing(clicking) an image (in a separate activity) and deleting it.
My problem is with refreshing the layout of the fragment to reflect a deleted image. Currently the following function is being called to deal with this:
public ViewGroup removeNoteImageFromView(String location) {
List<String> imageLinks = new ArrayList<String>();
for (String string : imageLocations) {
if (string.equalsIgnoreCase(location)) {
break;
}
imageLinks.add(string);
}
//REMOVE ALL THE IMAGEVIEWS from the Linear Layout
LinearLayout linear = (LinearLayout) rootView.findViewById(R.id.imageContainer);
if (linear.getChildCount() != 0) {
linear.removeAllViewsInLayout();
linear.refreshDrawableState();
linear.postInvalidate();
}
imageLocations.addAll(imageLinks);
//Add them all back from the new array
String root = Environment.getExternalStorageDirectory().toString();
for (String string : imageLinks) {
Bitmap myBitmap = BitmapFactory.decodeFile((new File(root +"/saved_images/"+string)).getAbsolutePath());
addImage(myBitmap);
}
return linear;
}
All this code does is hide all thumbnails which is called by linear.removeAllViewsInLayout(). However the following two line are what I thought would reload the layout on screen but they appear to have no effect whatsoever.
Please note I have tried linear.invalidate() as well as postInvalidate and still get nothing.
The correct image is deleted from the device as this is dealt with elsewhere so when I go back to this fragment by reselecting it in the menu everything is displayed correctly.
Replace this:
linear.refreshDrawableState();
linear.postInvalidate();
With this:
linear.requestLayout();
#Override
public View getView(int position, View convertView, ViewGroup parent) {
// Your code is here...
// for refresh view use..
convertView.invalidate();
}
Ok so I finally got it!
I feel a bit stupid as the code works fine but the root path was incorrect so it wasn't finding the images to add back into the view.
Thank you for all the responses and help. Sorry for my newbieness (I've only been properly using Java for a couple of weeks).
I have a basic android application that has several pages accessible from the home page, anyways I change the layout by doing
public void main(View view) {
setContentView(R.layout.main);
}
and changing the layout to the main game page. Now I want to add characters to it and so I added protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint green = new Paint();
green.setColor(Color.GREEN);
Rect theRect = new Rect();
theRect.set(0,0,canvas.getWidth()/2,canvas.getHeight()/2);
canvas.drawRect(theRect, green);
}
but I only want to call it for the "main" or the scene/layout that the game is played in. It appears to not be called at all and that may be due to the fact that I do not completely understand the relationship between the xml and multiple java files and functions. I'm new to android so this may be a stupid question, I just couldn't find anything with multiple web searches, with no luck.
You can add your game view into activity class:
Class GameView extends View/SurfaceView
{
//-- contains onDraw() method
}
To add this game view into your activity, you have to do
get reference of layout in whioch you want to add this gameview.
eg: LinearLayout layout=(LinearLayout) findViewById(R.id.linearlayout);
Add GameView into this layout
eg: layout.addView(new GameView());
For more detail, you can get reference from http://www.edu4java.com/en/androidgame/androidgame3.html
Hope this helps you
I have an activity that has a TabHost containing a set of TabSpecs each with a listview containing the items to be displayed by the tab. When each TabSpec is created, I set an icon to be displayed in the tab header.
The TabSpecs are created in this way within a setupTabs() method which loops to create the appropriate number of tabs:
TabSpec ts = mTabs.newTabSpec("tab");
ts.setIndicator("TabTitle", iconResource);
ts.setContent(new TabHost.TabContentFactory(
{
public View createTabContent(String tag)
{
...
}
});
mTabs.addTab(ts);
There are a couple of instances where I want to be able to change the icon which is displayed in each tab during the execution of my program. Currently, I am deleting all the tabs, and calling the above code again to re-create them.
mTabs.getTabWidget().removeAllViews();
mTabs.clearAllTabs(true);
setupTabs();
Is there a way to replace the icon that is being displayed without deleting and re-creating all of the tabs?
The short answer is, you're not missing anything. The Android SDK doesn't provide a direct method to change the indicator of a TabHost after it's been created. The TabSpec is only used to build the tab, so changing the TabSpec after the fact will have no effect.
I think there's a workaround, though. Call mTabs.getTabWidget() to get a TabWidget object. This is just a subclass of ViewGroup, so you can call getChildCount() and getChildAt() to access individual tabs within the TabWidget. Each of these tabs is also a View, and in the case of a tab with a graphical indicator and a text label, it's almost certainly some other ViewGroup (maybe a LinearLayout, but it doesn't matter) that contains an ImageView and a TextView. So with a little fiddling with the debugger or Log.i, you should be able to figure out a recipe to get the ImageView and change it directly.
The downside is that if you're not careful, the exact layout of the controls within a tab could change and your app could break. Your initial solution is perhaps more robust, but then again it might lead to other unwanted side effects like flicker or focus problems.
Just to confirm dominics answer, here's his solution in code (that actually works):
tabHost.setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
if (TAB_MAP.equals(tabId)) {
ImageView iv = (ImageView) tabHost.getTabWidget().getChildAt(0).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_map_black));
iv = (ImageView) tabHost.getTabWidget().getChildAt(1).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_list_white));
} else if (TAB_LIST.equals(tabId)) {
ImageView iv = (ImageView) tabHost.getTabWidget().getChildAt(0).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_map_white));
iv = (ImageView) tabHost.getTabWidget().getChildAt(1).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_list_black));
}
}
});
Of course it's not polished at all and using those direct indices in getChildAt() is not nice at all...
See my post with code example regarding Customized Android Tabs.
Thanks
Spct
This is what I did and it works for me. I created this function in the activity that extends from TabBarActivity
public void updateTab(int stringID) {
ViewGroup identifyView = (ViewGroup)getTabWidget().getChildAt(0);
TextView v = (TextView)identifyView.getChildAt(identifyView.getChildCount() - 1);
v.setText(stringID);
}
You can modify this function to change the image instead of text or you can change both, also you can modify this to get any tab child. I was particularly interested in modifying the text of the first tab at runtime.
I called this function from the relevant activity using this call
getParent().updateTab(R.string.tab_bar_analyze);
Try This:
tabHost.setOnTabChangedListener(new OnTabChangeListener() {
public void onTabChanged(String tabId) {
if (TAB_MAP.equals(tabId)) {
ImageView iv = (ImageView) tabHost.getTabWidget().getChildAt(0).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_map_black));
iv = (ImageView) tabHost.getTabWidget().getChildAt(1).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_list_white));
} else if (TAB_LIST.equals(tabId)) {
ImageView iv = (ImageView) tabHost.getTabWidget().getChildAt(0).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_map_white));
iv = (ImageView) tabHost.getTabWidget().getChildAt(1).findViewById(android.R.id.icon);
iv.setImageDrawable(getResources().getDrawable(R.drawable.tab_list_black));
}
}
});