Horizontal scrolling grid view - android

I know it is not possible in Android to scroll grid view horizontally. But what I am doing is adding image buttons dynamically inside horizontal scroll view like this:
public class HorizontalScroller extends Activity {
static int l=0;
private Rect mTempRect = new Rect();
static int r1=0;
static int t=0;
static int b=0;
static int x=0;
static int y=0;
//Button[] b1 = new Button[100];
ImageButton btn[][] = new ImageButton[10][10];
//ImageButton b1 = new ImageButton(this);
/** Called when the activity is first created. */
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
LinearLayout rl = (LinearLayout)findViewById(R.id.widget92);
LinearLayout.LayoutParams params1 = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT,LayoutParams.WRAP_CONTENT);
for(int i=0;i<4;i++)
{
for(int j=0;j<10;j++)
{System.out.println("helo");
/* l=l+100;
r1=r1+100;
t=t+100;
b=b+100;*/
//button();
//ImageButton btn=new ImageButton(this);
/* Rect r = mTempRect;
r.left=10;
r.top=10;
r.right=10;
r.bottom=10;
btn[i][j].getDrawingRect(r);*/
//btn[i][j].setId(j);
Rect r = mTempRect;
r.set(0,0,0,0);
Rect r2 = mTempRect;
r2.set(0,20,0,20);
btn[i][j]=new ImageButton(this);
btn[i][j]. setBackgroundResource(R.drawable.icon);
btn[i][j].setMinimumWidth(20);
btn[i][j].setMinimumHeight(20);
params1.setMargins(5, 5, 5,5);
rl.addView(btn[i][j],params1);
System.out.println("1="+btn[i][j].getTop());
System.out.println("2="+btn[i][j].getLeft());
System.out.println("3="+btn[i][j].getRight());
System.out.println("4="+btn[i][j].getBottom());
}
}
}
}
but I am getting all image buttons in a single line. How can I implement them in a grid like structure?

Implementing a horizontally scrolling GridView involves copying a few of the Android source code classes into your codebase (AdapterView, AbsListView, GridView, ScrollBarDrawable) and adding in code to handle the horizontal code. This is mainly copying some of the code and changing top to left, bottom to right, etc. The main reason for having to copy instead of extending is the final nature of those classes.
I implemented a horizontally scrolling GridView a while ago and finally got around to pushing to github:
https://github.com/jess-anders/two-way-gridview

You can
use a TableLayout inside a HorizontalScrollView, or
stay with your approach with an horizontal LinearLayout but adding vertical LinearLayouts instead of directly the images. E.g., adding three to four images per vertical LinearLayout in portrait, and redrawing to add only two in landscape.
I would try the TableLayout approach first.
PS1: for next time, try to remove all the non-relevant code (the less code is there, the easier is to understand what you did).
PS2: Remember that System.out is usually redirected to /dev/null and thus lost, so I strongly suggest you to use Log.d instead.
Complete example
Adapt this to the onCreate() method or wherever you need it:
public void horizontalScrollGalleryLayout () {
HorizontalScrollView sv = new HorizontalScrollView(this);
LinearLayout llh = new LinearLayout(this);
llh.setOrientation(LinearLayout.HORIZONTAL);
LinearLayout.LayoutParams layoutParamsTV = new LinearLayout.LayoutParams(40, 40);
LinearLayout.LayoutParams layoutParamsLL = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT, LinearLayout.LayoutParams.WRAP_CONTENT);
for (int i=0; i<20; i++) {
LinearLayout llv = new LinearLayout(this);
llv.setOrientation(LinearLayout.VERTICAL);
TestView testView1 = new TestView(this, Color.rgb(i*12, 0, 0));
TestView testView2 = new TestView(this, true, Color.rgb(i*12, i*12, 0));
TestView testView3 = new TestView(this, true, Color.rgb(0, i*12, 0));
llv.addView(testView1, layoutParamsTV);
llv.addView(testView2, layoutParamsTV);
llv.addView(testView3, layoutParamsTV);
llh.addView(llv, layoutParamsLL);
}
sv.addView(llh, layoutParamsLL);
setContentView(sv);
}
I'm using a very simple View as an example:
public class TestView extends View {
Context context;
int color;
public TestView(Context context, int color) {
super(context);
this.context = context;
this.color = color;
}
#Override
public void onDraw (Canvas canvas) {
super.onDraw(canvas);
this.setBackgroundColor(Color.LTGRAY);
Paint paint = new Paint (Paint.ANTI_ALIAS_FLAG);
paint.setColor(color);
canvas.drawCircle(20, 20, 20, paint);
}
}

There is a very easy trick.
Rotate the grid view by 270 degree and set number of columns as 2.
Rotate each item to 90 degree (so that the items are displayed as original orientation).
This might be useful for some!!

I have done this way:
activity_main.xml:
<HorizontalScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<GridView
android:id="#+id/gridView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</GridView>
</LinearLayout>
</HorizontalScrollView>
MainActivity.java:
GridView gridView = (GridView) findViewById(R.id.gridView);
gridView.setNumColumns(arrayList.size());
GridViewAdapter gridViewAdapter = new GridViewAdapter(mContext, arrayList);
gridView.setAdapter(gridViewAdapter);
// Set dynamic width of Gridview
setDynamicWidth(gridView);
Add below method:
private void setDynamicWidth(GridView gridView) {
ListAdapter gridViewAdapter = gridView.getAdapter();
if (gridViewAdapter == null) {
return;
}
int totalWidth;
int items = gridViewAdapter.getCount();
View listItem = gridViewAdapter.getView(0, null, gridView);
listItem.measure(0, 0);
totalWidth = listItem.getMeasuredWidth();
totalWidth = totalWidth*items;
ViewGroup.LayoutParams params = gridView.getLayoutParams();
params.width = totalWidth;
gridView.setLayoutParams(params);
}
Hope this will help you.

I have already posted this answer here, but both questions are
identical...
There is a nice solution in Android from now on : HorizontalGridView.
1. Gradle dependency
dependencies {
compile 'com.android.support:leanback-v17:23.1.0'
}
2. Add it in your layout
your_activity.xml
<!-- your stuff before... -->
<android.support.v17.leanback.widget.HorizontalGridView
android:layout_width="wrap_content"
android:layout_height="80dp"
android:id="#+id/gridView"
/>
<!-- your stuff after... -->
3. Layout grid element
Create a layout for your grid element ( grid_element.xml ). I have created a simple one with only one button in it.
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:layout_width="match_parent"
android:layout_height="match_parent">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="New Button"
android:id="#+id/button" />
</LinearLayout>
4. Create an adapter
Highly inspired by this link : https://gist.github.com/gabrielemariotti/4c189fb1124df4556058
public class GridElementAdapter extends RecyclerView.Adapter<GridElementAdapter.SimpleViewHolder>{
private Context context;
private List<String> elements;
public GridElementAdapter(Context context){
this.context = context;
this.elements = new ArrayList<String>();
// Fill dummy list
for(int i = 0; i < 40 ; i++){
this.elements.add(i, "Position : " + i);
}
}
public static class SimpleViewHolder extends RecyclerView.ViewHolder {
public final Button button;
public SimpleViewHolder(View view) {
super(view);
button = (Button) view.findViewById(R.id.button);
}
}
#Override
public SimpleViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
final View view = LayoutInflater.from(this.context).inflate(R.layout.grid_element, parent, false);
return new SimpleViewHolder(view);
}
#Override
public void onBindViewHolder(SimpleViewHolder holder, final int position) {
holder.button.setText(elements.get(position));
holder.button.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
Toast.makeText(context, "Position =" + position, Toast.LENGTH_SHORT).show();
}
});
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public int getItemCount() {
return this.elements.size();
}
}
5. Initialize it in your activity :
private HorizontalGridView horizontalGridView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.your_activity);
horizontalGridView = (HorizontalGridView) findViewById(R.id.gridView);
GridElementAdapter adapter = new GridElementAdapter(this);
horizontalGridView.setAdapter(adapter);
}

Use recyclerview with setting its gridlayout as layout manager and set it to horizontal scroll
your recycle view.setLayoutManager(new GridLayoutManager(getActivity(),2, LinearLayoutManager.HORIZONTAL, false))
here 2 is the column span for grid

Related

How to add a variable number of TextViews and EditViews in activity

I'm currently trying to add a user-defined number of TextViews and EditText to an activity, but can't seem to do it other than hard-coding it by creating a variety of different activities.
The objective of this activity is to take the names of the players, the number of which is relayed by the intent extra from the preceding activity.
I'm trying to add both a TextView saying "Player X: " and an EditText to type the name of the player for each player
I know from this post: How to create a variable number of textviews in android that I have to do this programmatically, however, it does not seem to work for me (the activity remains blank when tested)
I have tried creating a temp LinearLayout to which I add the two views in a for(), still nothing.
Any ideas? Am I on the right track?
Best regards
[EDIT] Code is here :
public class players extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_players);
Bundle extras = new Bundle();
final int numPlayers = extras.getInt("num");
final LinearLayout myLayout = findViewById(R.id.lin_Re);
final ArrayList<Player> players = new ArrayList<>();
int size = numPlayers; // total number of TextViews to add
TextView[] tv = new TextView[size];
TextView temp;
EditText[] et = new EditText[size];
EditText temp2;
LinearLayout temp3;
for (int i = 0; i < size; i++)
{
temp = new TextView(this);
temp2 = new EditText(this);
temp3 = new LinearLayout(this);
temp.setText("Player " + i + " : "); //arbitrary task
// add the textview to the linearlayout
temp3.addView(temp);
temp3.addView(temp2);
tv[i] = temp;
et[i] = temp2;
myLayout.addView(temp3);
}
<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:gravity="center"
android:id="#+id/lin_Re">
</LinearLayout>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/b_send"/>
</LinearLayout>
There is 2 way to achieve this:
1. Use a RecyclerView [Recommended]
2. Add TextView and EditText ( which is nested in a Horizontal LinearLayout) into a Vertical LinearLayout nested in a ScrollView programmatically
The first solution I describe below is quite simple if you're familiar with RecyclerView or ListView, the second solution (your current track) is a bit tricky but still achievable.
Solution 1:
MainActivity
public class MainActivity extends AppCompatActivity {
RecyclerView mPlayerList;
List<String> mPlayerNames;
PlayerAdapter mAdapter;
EditText mInput;
Button mCreateButton;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mPlayerNames = new ArrayList<>();
// setup recycler view
mPlayerList = findViewById(R.id.player_list);
mPlayerList.setLayoutManager(new LinearLayoutManager(this));
mAdapter = new PlayerAdapter();
mPlayerList.setAdapter(mAdapter);
// setup input EditText
mInput = findViewById(R.id.input);
// setup Create button
mCreateButton = findViewById(R.id.create_button);
mCreateButton.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
// clear old player names
mPlayerNames.clear();
// read user input: number of player:
String input = mInput.getText().toString();
int numberOfPlayer;
try {
numberOfPlayer = Integer.parseInt(input);
} catch (NumberFormatException e) {
Toast.makeText(MainActivity.this, "Invalid input!!!", Toast.LENGTH_SHORT).show();
return;
}
for (int i = 0; i < numberOfPlayer; ++i) {
mPlayerNames.add("Player #" + (i + 1));
}
// make change on recycler view
mAdapter.notifyDataSetChanged();
// dismiss keyboard
InputMethodManager imm = (InputMethodManager)getSystemService(Context.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(mInput.getWindowToken(), 0);
}
});
}
private class PlayerAdapter extends RecyclerView.Adapter<PlayerAdapter.PlayerHolder> {
#Override
public PlayerHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View v = LayoutInflater.from(MainActivity.this).inflate(R.layout.item_layout, parent, false);
return new PlayerHolder(v);
}
#Override
public void onBindViewHolder(PlayerHolder holder, int position) {
holder.bind(mPlayerNames.get(position));
}
#Override
public int getItemCount() {
return mPlayerNames.size();
}
public class PlayerHolder extends RecyclerView.ViewHolder {
TextView mPlayerLabel;
EditText mPlayerName;
public PlayerHolder(View itemView) {
super(itemView);
mPlayerLabel = itemView.findViewById(R.id.player_label);
mPlayerName = itemView.findViewById(R.id.player_name);
}
public void bind(String playerName) {
mPlayerLabel.setText(playerName);
mPlayerName.setHint("Name of " + playerName);
}
}
}
}
The sample project can be found here:
https://github.com/raiytu4/stackcase004

How to show exactly ten rows in RecyclerView

I would like to always display exactly ten rows in a RecyclerView. RecyclerView does not have a configurable setting for this. One approach is to calculate the size of each row. I would like the table to take up half the screen and always show 0..10 items within that area. If more than 10 items the user would scrooll to see the items. Right now the default behavior of RecyclerView seems to be to keep pushing everything down as it grows.
#Override
public int getItemCount() {
if(list.size()>10){
return 10;
}else{
return list.size();
}
}
In your recycler view adapter class return get item count to 10 if size of array or list is greater than 10
Your guess is right it's working with a dynamic computation of row height, here is an example:
Simple class standing for data you want to display:
public class CustomItem {
private int counter;
public CustomItem(int counter) {
this.counter = counter;
}
public int getCounter() {
return counter;
}
public void setCounter(int counter) {
this.counter = counter;
}
}
And simple layout to display CustomItem in a list:
<?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="wrap_content"
android:background="#android:color/darker_gray">
<TextView
android:id="#+id/txvTest"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="Test"/>
</RelativeLayout>
RecyclerAdapter for this class, you will see that we set row height programmatically in onBindViewHolder method:
public class CustomItemRecyclerAdapter extends RecyclerView.Adapter<CustomItemRecyclerAdapter.SimpleItemViewHolder> {
private static int NB_OF_ITEM_TO_DISPLAY = 10;
private List<CustomItem> customItems;
private Context context;
private int rowHeight;
public class SimpleItemViewHolder extends RecyclerView.ViewHolder {
TextView txvTest;
RelativeLayout container;
public SimpleItemViewHolder(View itemView) {
super(itemView);
txvTest = (TextView) itemView.findViewById(R.id.txvTest);
container = (RelativeLayout) itemView;
}
}
public CustomItemRecyclerAdapter(Context context, List<CustomItem> customItems) {
this.context = context;
this.customItems = customItems;
}
public void setItemHeight(int parentHeightInPx){
// Height of a row is just parent height divided by number of row to display
this.rowHeight = parentHeightInPx / CustomItemRecyclerAdapter.NB_OF_ITEM_TO_DISPLAY;
// Notify adapter because items will need to be redraw to use newly set height
this.notifyDataSetChanged();
}
#Override
public SimpleItemViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
View itemView = LayoutInflater.from(context).inflate(R.layout.custom_item, parent, false);
return new SimpleItemViewHolder(itemView);
}
#Override
public void onBindViewHolder(SimpleItemViewHolder holder, int position) {
CustomItem item = customItems.get(position);
holder.txvTest.setText("Item " + item.getCounter());
holder.txvTest.setBackgroundColor(item.getCounter());
// Row size magic is here!
RelativeLayout.LayoutParams params = new RelativeLayout.LayoutParams(RelativeLayout.LayoutParams.MATCH_PARENT, rowHeight);
holder.container.setLayoutParams(params);
}
#Override
public int getItemCount() {
return customItems.size();
}
}
Activity layout, with both a TextView used as placeholder for half the screen and the RecyclerView:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_weight="1"
android:background="#color/colorAccent"
android:text="TEST"/>
<android.support.v7.widget.RecyclerView
android:id="#+id/a_main_rcv_items"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/colorPrimary"
android:layout_weight="1"
android:scrollbars="vertical"/>
</LinearLayout>
And Activity code with comments to understand how it works ;):
public class MainActivity extends AppCompatActivity {
private RecyclerView recyclerView;
private CustomItemRecyclerAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// Link to layout recycler view
recyclerView = (RecyclerView) findViewById(R.id.a_main_rcv_items);
// Create a simple linear layout manager and set it to recyclerview
RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
recyclerView.setLayoutManager(layoutManager);
// Create an instance of our custom Adapter
adapter = new CustomItemRecyclerAdapter(MainActivity.this, generateItems(20));
// Set this adapter
recyclerView.setAdapter(adapter);
// Listen for recycler view layout change event to get its height and then compute and set new rows height
recyclerView.addOnLayoutChangeListener(new View.OnLayoutChangeListener() {
#Override
public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) {
// Set item height using height of recyclerView
adapter.setItemHeight(view.getHeight());
// Need to simulate a scroll to force a redraw of recycler rows with new height... I have not find better for now...
recyclerView.scrollBy(0,1);
}
});
}
private List<CustomItem> generateItems(int nb) {
ArrayList<CustomItem> items = new ArrayList<>(nb);
for (int i = 1; i < nb + 1; i++) {
items.add(new CustomItem(i));
}
return items;
}
}

Android - How to create a transition from an item in listview to a whole activity?

What I want is that when the user clicks a list item in a ListView, it converts to a whole activity (as you can see in the following example), but I was not able to find a tutorial explaining this and, actually, I do not know how this movement is called.
In other words, what I want to achieve is:
Increase List Item elevation when it is clicked (as you can see in the right gif)
Expand and transform list item to the next fragment/activity layout that contains detailed information about the clicked item
I have tried a lot of transitions but with no luck. Can anyone help me out to accomplish this?
I build a small sample application that transitions between two activities with the desired effect:
However the transitions in the provided gifs are slightly different. The
transition in the gif on the left side transitions the list element into the content area of the second activity (Toolbar stays in place). In the gif on the right side the transition transforms the list element into the complete screen of the second activity. The following code provides the effect in the left gif. However it should be possible to adapt the solution with minor modifications to achieve the transition in the right gif.
Note this only works on Lollipop. However it is possible to mock a different effect on older devices.
Furthermore the sole purpose of the provided code is to show how it could be done. Don't use this directly in your app.
MainActivity:
public class MainActivity extends AppCompatActivity {
MyAdapter myAdapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
ListView listView = (ListView) findViewById(R.id.list_view);
myAdapter = new MyAdapter(this, 0, DataSet.get());
listView.setAdapter(myAdapter);
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, final View view, final int position, long id) {
startTransition(view, myAdapter.getItem(position));
}
});
}
private void startTransition(View view, Element element) {
Intent i = new Intent(MainActivity.this, DetailActivity.class);
i.putExtra("ITEM_ID", element.getId());
Pair<View, String>[] transitionPairs = new Pair[4];
transitionPairs[0] = Pair.create(findViewById(R.id.toolbar), "toolbar"); // Transition the Toolbar
transitionPairs[1] = Pair.create(view, "content_area"); // Transition the content_area (This will be the content area on the detail screen)
// We also want to transition the status and navigation bar barckground. Otherwise they will flicker
transitionPairs[2] = Pair.create(findViewById(android.R.id.statusBarBackground), Window.STATUS_BAR_BACKGROUND_TRANSITION_NAME);
transitionPairs[3] = Pair.create(findViewById(android.R.id.navigationBarBackground), Window.NAVIGATION_BAR_BACKGROUND_TRANSITION_NAME);
Bundle b = ActivityOptionsCompat.makeSceneTransitionAnimation(MainActivity.this, transitionPairs).toBundle();
ActivityCompat.startActivity(MainActivity.this, i, b);
}
}
activity_main.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:transitionName="toolbar" />
<ListView
android:id="#+id/list_view"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
DetailActivity:
public class DetailActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_detail);
setSupportActionBar((Toolbar) findViewById(R.id.toolbar));
long elementId = getIntent().getLongExtra("ITEM_ID", -1);
Element element = DataSet.find(elementId);
((TextView) findViewById(R.id.title)).setText(element.getTitle());
((TextView) findViewById(R.id.description)).setText(element.getDescription());
// if we transition the status and navigation bar we have to wait till everything is available
TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar(this);
// set a custom shared element enter transition
TransitionHelper.setSharedElementEnterTransition(this, R.transition.detail_activity_shared_element_enter_transition);
}
}
activity_detail.xml:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<android.support.v7.widget.Toolbar
android:id="#+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
android:background="#color/colorPrimary"
android:transitionName="toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#abc"
android:orientation="vertical"
android:paddingBottom="200dp"
android:transitionName="content_area"
android:elevation="10dp">
<TextView
android:id="#+id/title"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/description"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>
</LinearLayout>
detail_activity_shared_element_enter_transition.xml (/res/transition/):
<?xml version="1.0" encoding="utf-8"?>
<transitionSet xmlns:android="http://schemas.android.com/apk/res/android"
android:transitionOrdering="together">
<changeBounds/>
<changeTransform/>
<changeClipBounds/>
<changeImageTransform/>
<transition class="my.application.transitions.ElevationTransition"/>
</transitionSet>
my.application.transitions.ElevationTransition:
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
public class ElevationTransition extends Transition {
private static final String PROPNAME_ELEVATION = "my.elevation:transition:elevation";
public ElevationTransition() {
}
public ElevationTransition(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override
public void captureStartValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
#Override
public void captureEndValues(TransitionValues transitionValues) {
captureValues(transitionValues);
}
private void captureValues(TransitionValues transitionValues) {
Float elevation = transitionValues.view.getElevation();
transitionValues.values.put(PROPNAME_ELEVATION, elevation);
}
#Override
public Animator createAnimator(ViewGroup sceneRoot, TransitionValues startValues, TransitionValues endValues) {
if (startValues == null || endValues == null) {
return null;
}
Float startVal = (Float) startValues.values.get(PROPNAME_ELEVATION);
Float endVal = (Float) endValues.values.get(PROPNAME_ELEVATION);
if (startVal == null || endVal == null || startVal.floatValue() == endVal.floatValue()) {
return null;
}
final View view = endValues.view;
ValueAnimator a = ValueAnimator.ofFloat(startVal, endVal);
a.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
#Override
public void onAnimationUpdate(ValueAnimator animation) {
view.setElevation((float)animation.getAnimatedValue());
}
});
return a;
}
}
TransitionHelper:
public class TransitionHelper {
public static void fixSharedElementTransitionForStatusAndNavigationBar(final Activity activity) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
final View decor = activity.getWindow().getDecorView();
if (decor == null)
return;
activity.postponeEnterTransition();
decor.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#TargetApi(Build.VERSION_CODES.LOLLIPOP)
#Override
public boolean onPreDraw() {
decor.getViewTreeObserver().removeOnPreDrawListener(this);
activity.startPostponedEnterTransition();
return true;
}
});
}
public static void setSharedElementEnterTransition(final Activity activity, int transition) {
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP)
return;
activity.getWindow().setSharedElementEnterTransition(TransitionInflater.from(activity).inflateTransition(transition));
}
}
So what are the different parts here:
We have two activities. During the transition four views are transitioned between the activities.
Toolbar: like in the left gif the toolbar doesn't move with the rest of the content.
ListView element View -> becomes the content view of the DetailActivity
StatusBar and NavigationBar Background: If we don't add these views to the set of transitioned views they will fade out and back in during the transition. This however requires to delay the enter transition (see: TransitionHelper.fixSharedElementTransitionForStatusAndNavigationBar)
In the MainActivity the transitioned views are added to the Bundle that is used to start the DetailActivity. Furthermore the transitioned views need to be named (transitionName) in both activities. This can be done in the layout xml as well as programatically.
The default set of transitions, that is used during the shared element transition, affects different aspects of the view(for example: view bounds - see 2). However differences in the elevation of a view are not animated. This is why the presented solution utilizes the custom ElevationTransition.
try this.. Material-Animations
blueIconImageView.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
Intent i = new Intent(MainActivity.this, SharedElementActivity.class);
View sharedView = blueIconImageView;
String transitionName = getString(R.string.blue_name);
ActivityOptions transitionActivityOptions = ActivityOptions.makeSceneTransitionAnimation(MainActivity.this, sharedView, transitionName);
startActivity(i, transitionActivityOptions.toBundle());
}
});
The Animation you need is called Activity Transitions between shared elements.
By Research I found that you should:
Put your ListView view in a relativeLayout
OnClick, inflate a copy of your renderer
Find the global coordinates for where the renderer sits in
relationship to the parent of the ListView
Add the copied renderer to the RelativeLayout (parent of ListView)
Animate the listView away
On the end of that animate, animate your new renderer
Profit!
public class MainActivity extends Activity {
private RelativeLayout layout;
private ListView listView;
private MyRenderer selectedRenderer;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
layout = new RelativeLayout(this);
setContentView(layout);
listView = new ListView(this);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.MATCH_PARENT, RelativeLayout.LayoutParams.MATCH_PARENT);
layout.addView(listView, rlp);
listView.setAdapter(new MyAdapter());
listView.setOnItemClickListener(new AdapterView.OnItemClickListener() {
#Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
// find out where the clicked view sits in relationship to the
// parent container
int t = view.getTop() + listView.getTop();
int l = view.getLeft() + listView.getLeft();
// create a copy of the listview and add it to the parent
// container
// at the same location it was in the listview
selectedRenderer = new MyRenderer(view.getContext());
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(view.getWidth(), view
.getHeight());
rlp.topMargin = t;
rlp.leftMargin = l;
selectedRenderer.textView.setText(((MyRenderer) view).textView.getText());
layout.addView(selectedRenderer, rlp);
view.setVisibility(View.INVISIBLE);
// animate out the listView
Animation outAni = new TranslateAnimation(Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, -1f, Animation.RELATIVE_TO_SELF, 0f,
Animation.RELATIVE_TO_SELF, 0f);
outAni.setDuration(1000);
outAni.setFillAfter(true);
outAni.setAnimationListener(new Animation.AnimationListener() {
#Override
public void onAnimationStart(Animation animation) {
}
#Override
public void onAnimationRepeat(Animation animation) {
}
#Override
public void onAnimationEnd(Animation animation) {
ScaleAnimation scaleAni = new ScaleAnimation(1f,
1f, 1f, 2f,
Animation.RELATIVE_TO_SELF, 0.5f,
Animation.RELATIVE_TO_SELF, 0.5f);
scaleAni.setDuration(400);
scaleAni.setFillAfter(true);
selectedRenderer.startAnimation(scaleAni);
}
});
listView.startAnimation(outAni);
}
});
}
public class MyAdapter extends BaseAdapter {
#Override
public int getCount() {
return 10;
}
#Override
public String getItem(int position) {
return "Hello World " + position;
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
MyRenderer renderer;
if (convertView != null)
renderer = (MyRenderer) convertView;
else
renderer = new MyRenderer(MainActivity.this);
renderer.textView.setText(getItem(position));
return renderer;
}
}
public class MyRenderer extends RelativeLayout {
public TextView textView;
public MyRenderer(Context context) {
super(context);
setPadding(20, 20, 20, 20);
setBackgroundColor(0xFFFF0000);
RelativeLayout.LayoutParams rlp = new RelativeLayout.LayoutParams(
RelativeLayout.LayoutParams.WRAP_CONTENT, RelativeLayout.LayoutParams.WRAP_CONTENT);
rlp.addRule(CENTER_IN_PARENT);
textView = new TextView(context);
addView(textView, rlp);
}
} }
Try this spectacular webpage # Getting Started with Activity & Fragment Transitions (part 1). Here they talked about Activity and Fragment Transitions. I have not tried it. My view is that Fragment Transitions is better and less computer intensive, so it's a good start. And you may not need to change Toolbars, you can show/hide them.
Another good SO link is # Animate the transition between fragments, look at the best answer. In that post, they talked about objectAnimator.
Another opinion is about the sample animation you posted, it does not show a smooth animation from one art to another. It is less impressive when the animation is not smooth.
Good luck, have fun, keep us all posted.

ListView or LinearLayout - creating Buttons dynamically

When a user enters a word, it creates Buttons - one Button per letter of the word:
Illustration:
If the user enters "so" it creates 2 Buttons - 's', 'o'
If the user enters "make" it creates 4 Buttons - 'm', 'a', 'k', 'e'
I was having a hard time deciding how I should design this. Ultimately I decided to do the following: Each word is added to a vertical LinearLayout. And for each word, each letter is added to a horizontal LinearLayout. So it's a LinearLayout within a LinearLayout approach.
Here's the code I created which works:
//creates words dynamically
public void makeNewWord(LinearLayout ll, View v, EditText e){
//the horizontal linear layout
LinearLayout linearLayout2 = new LinearLayout(v.getContext());
linearLayout2.setOrientation(LinearLayout.HORIZONTAL);
//the parameters for the horizontal linear layout
LinearLayout.LayoutParams rlp = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT);
//e is the user input
int size = e.getText().toString().length();
for (int i=0; i<size; i++){
final Button dynamicButtons = new Button(v.getContext());
dynamicButtons.setLayoutParams(rlp);
//add the buttons to the horizontal linear layout
linearLayout2.addView(dynamicButtons, rlp);
}
// ll is the vertical linear layout which I created in xml
// so for each entered word, I am adding horizontal linear layouts to my vertical layout
ll.addView(linearLayout2, 0);
}
But now I realized it's probably more efficient using a ListView, especially since I want to make the list of words to be expandable and collapsible. But Is it possible to create the above illustration using a ListView? How would I go about doing so?
I tried creating an ArrayAdapter as follows: ArrayAdapter<LinearLayout> adapter = new ArrayAdapter<LinearLayout>(this, R.id.listview). So basically it would be a ListView of horizontal LinearLayouts. Or should I make an ArrayAdapter of Buttons instead? What is the correct approach?
I can give some idea you can transform this idea in code
1. onTextChanged() method try to get length of text.
2. If you able to get text length then by subString() method get last entered text
3. Then recreate new button instance
You can use a TableLayout for this.
test.xml
<ScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_height="match_parent"
android:layout_width="match_parent">
<TableLayout
android:id="#+id/table_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
</TableLayout>
</ScrollView>
Activity Code
private TableLayout tableLayout;
private HashMap<String, TableRow> tableRows;
#Override
public void onCreate(Bundle savedInstanceState) {
setContentView(R.layout.test);
super.onCreate(savedInstanceState);
tableLayout = (TableLayout) findViewById(R.id.table_layout);
tableRows = new HashMap<String, TableRow>();
}
public void addWord(String word) {
if (!tableRows.containsKey(word)) {
TableRow tableRow = new TableRow(this);
for (int i = 0; i < word.length(); i++) {
String letter = String.valueOf(word.charAt(i));
Button btnLetter = new Button(this);
btnLetter.setText(letter);
tableRow.addView(btnLetter);
}
tableRows.put(word, tableRow);
tableLayout.addView(tableRow);
}
}
public void removeWord(String word) {
TableRow tableRow = tableRows.remove(word);
if (tableRow != null) {
tableLayout.removeView(tableRow);
}
}
public void showWord(String word) {
TableRow tableRow = tableRows.get(word);
if (tableRow != null) {
tableRow.setVisibility(View.VISIBLE);
}
}
public void hideWord(String word) {
TableRow tableRow = tableRows.get(word);
if (tableRow != null) {
tableRow.setVisibility(View.GONE);
}
}
Assuming you want a specific button setup, you can inflate an xml button layout dynamically. See here for details.
I would just use a horizontal list view per word.
I you want to be fancy you create a custom layout manager and the new RecyclerView.
Each character of your word would be then a item in your list view. The layout then could be simply a button.
class ListAdapter extends BaseAdapter {
private final Context fContext;
private String mWord;
public ListAdapter(Context context) {
fContext = context;
}
public void updateWord(String word) {
mWord = word;
notifyDataSetChanged();
}
#Override
public int getCount() {
return mWord == null ? 0 : mWord.length();
}
#Override
public String getItem(int position) {
return String.valueOf(mWord.charAt(position));
}
#Override
public long getItemId(int position) {
return position;
}
#Override
public View getView(int position, View convertView, ViewGroup parent) {
Button button;
if (convertView == null) {
button = new Button(parent.getContext());
LayoutParams params = new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.WRAP_CONTENT);
button.setLayoutParams(params);
} else {
button = (Button) convertView;
}
button.setText(getItem(position));
return button;
}
}
On every text change you can then just update the list.
adapter.updateWord();
Be aware the code is just out of my head and i haven't tested this, but should be enough to give you and idea.

Dynamic data loading on custom List-view with background container

I am totally confuse with my image list view.
I want to display 2 video poster and text view in a single row with background container ( check attach image of train)
This is single cell of vertical List view.
Depending on number of videos i have to display vertical list view but each row contain 2 video poster and text view at side of it video with train Engine image at start or end vice versa of row number.
To achieve this UI i write a custom adaptor in which i manage to display train wagon with related image-view by using relative layout.
but how can i manage on-click listener on particular item (particular video in row) on single row.and how can i add train image at start or end of each row
here is output of my code.
Here is my code
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
//setContentView(R.layout.main);
final Context context = CustomAdapterExample.this;
ListView ls2 = new ListView(context);
// clear previous results in the LV
ls2.setAdapter(null);
// populate
ArrayList<Device> videos = new ArrayList<Device>();
Device my_video;
for (int i=0;i<05;i++) {
my_video = new Device("video link","Video id");
videos.add(my_video);
}
CustomAdapter lvAdapter = new CustomAdapter(context, videos);
ls2.setAdapter(lvAdapter);
ls2.setOnItemClickListener(new OnItemClickListener()
{
public void onItemClick(AdapterView<?> arg0, View arg1,int arg2, long arg3)
{
Toast.makeText(getBaseContext(), "You clicked on "+arg2, Toast.LENGTH_LONG).show();
}
});
setContentView(ls2);
}
And here is adaptor
class CustomAdapterView extends LinearLayout {
public CustomAdapterView(Context context, Device device)
{
super( context );
//container is a horizontal layer
setOrientation(LinearLayout.HORIZONTAL);
setPadding(0, 6, 0, 6);
LinearLayout Mainview = new LinearLayout(context);
LinearLayout.LayoutParams Cellparams = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT);
Mainview.setLayoutParams(Cellparams);
ImageView firstImageContainer = new ImageView(context);
ImageView trackImage = new ImageView(context);
ImageView VideoViewContainer = new ImageView(context);
TextView firsttext= new TextView(context);
firsttext.setText("Testing of app");
firsttext.setTextColor(Color.RED);
firstImageContainer.setBackgroundResource(R.drawable.wagon);
VideoViewContainer.setBackgroundResource(R.drawable.video);
RelativeLayout layout = new RelativeLayout(context);
RelativeLayout.LayoutParams firstContainerParams = new RelativeLayout.LayoutParams(160, 80);
layout.setLayoutParams(firstContainerParams);
trackImage.setBackgroundResource(R.drawable.line);
RelativeLayout.LayoutParams trackRules = new RelativeLayout.LayoutParams(755,5);
trackRules.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
RelativeLayout.LayoutParams firstImageContainerParams = new RelativeLayout.LayoutParams(140, 90);
RelativeLayout.LayoutParams VideoViewContainerParams = new RelativeLayout.LayoutParams(70,60);
VideoViewContainerParams.addRule(RelativeLayout.CENTER_VERTICAL);
VideoViewContainerParams.setMargins(5, 0, 0, 0);
layout.addView(firstImageContainer, firstImageContainerParams);
layout.addView(VideoViewContainer, VideoViewContainerParams);
layout.addView(trackImage, trackRules);
ImageView secondImageContainer = new ImageView(context);
ImageView secondtrackImage = new ImageView(context);
ImageView secondVideoViewContainer = new ImageView(context);
secondImageContainer.setBackgroundResource(R.drawable.wagon);
secondVideoViewContainer.setBackgroundResource(R.drawable.video);
RelativeLayout secondLayout = new RelativeLayout(context);
RelativeLayout.LayoutParams secondContainerParams = new RelativeLayout.LayoutParams(160, 80);
secondLayout.setLayoutParams(firstContainerParams);
secondtrackImage.setBackgroundResource(R.drawable.line);
RelativeLayout.LayoutParams secondtrackRules = new RelativeLayout.LayoutParams(755,5);
trackRules.addRule(RelativeLayout.ALIGN_PARENT_BOTTOM);
RelativeLayout.LayoutParams secondImageContainerParams = new RelativeLayout.LayoutParams(140, 90);
RelativeLayout.LayoutParams secondVideoViewContainerParams = new RelativeLayout.LayoutParams(70,60);
secondVideoViewContainerParams.addRule(RelativeLayout.CENTER_VERTICAL);
secondVideoViewContainerParams.setMargins(5, 0, 0, 0);
secondLayout.addView(secondImageContainer, secondImageContainerParams);
secondLayout.addView(secondVideoViewContainer, secondVideoViewContainerParams);
secondLayout.addView(secondtrackImage, secondtrackRules);
firstContainerParams.addRule(RelativeLayout.ALIGN_LEFT);
secondImageContainerParams.addRule(RelativeLayout.ALIGN_RIGHT);
Mainview.addView(layout,firstContainerParams);
Mainview.addView(secondLayout,secondContainerParams);
addView(Mainview);
}
}
public class CustomAdapter extends BaseAdapter /*implements OnClickListener*/ {
public static final String LOG_TAG = "BI::CA";
private Context context;
private List<videoData> videolist;
public CustomAdapter(Context context, List<Device> videolist ) {
this.context = context;
this.videolist = videolist;
}
public int getCount() {
return videolist.size();
}
public Object getItem(int position) {
return videolist.get(position);
}
public long getItemId(int position) {
return position;
}
public View getView(int position, View convertView, ViewGroup parent)
{
Device device = videolist.get(position);
View v = new CustomAdapterView(this.context, device );
return v;
}
}
If my implementation is wrong than please suggest me some guidance.
gallery is deprecated in API 17 i can't use it.
Is it possible to crate such Ui by using tableview or grid view??
Any Help is Appreciated.
Finally I figure it to display All contain same as on other device by using Include tag in list view layout.
<HorizontalScrollView
android:id="#+id/horizontalScrollView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content" >
<include android:id="#+id/train2" layout="#layout/train2" />
</HorizontalScrollView>
In train I have this
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
<include android:id="#+id/boogi1" layout="#layout/boogi" />
<include android:id="#+id/boogi2" layout="#layout/boogi" />
<include android:id="#+id/engine" layout="#layout/engine" />
And to access each Image-view and textview i used
ImageView v1 = ((ImageView)vi.findViewById(R.id.train).findViewById(R.id.boogi1).findViewById(R.id.imageView1));
Thank you for support.
Just one question is it possible to change view for every row depending on position of row..
I think you need to try Custom Listview,,,
try this http://www.androidhive.info/2012/02/android-custom-listview-with-image-and-text/.

Categories

Resources