I have the following XML file that is built out of a custom layout that is created via Java code and 3 buttons inside a linear layout below it -
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:background="#color/grey_200"
android:layout_height="match_parent"
android:orientation="vertical">
<include layout="#layout/toolbar" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#color/grey_200"
android:gravity="center_vertical"
android:orientation="vertical"
tools:layout_height="500dp">
<com.etiennelawlor.tinderstack.ui.TinderStackLayout
android:id="#+id/activity_main_tinder_stack_layout"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal"
android:padding="5dp">
<Button
android:layout_width="wrap_content"
android:id="#+id/activity_main_delete_button"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#ff0000"
android:tag="1"
android:text="#string/activity_main_delete" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="#+id/activity_main_pass_button"
android:layout_margin="10dp"
android:background="#A9A9A9"
android:tag="2"
android:text="#string/activity_main_pass" />
<Button
android:layout_width="wrap_content"
android:id="#+id/activity_main_approve_button"
android:layout_height="wrap_content"
android:layout_margin="10dp"
android:background="#98FB98"
android:tag="3"
android:text="#string/activity_main_approve" />
</LinearLayout>
</LinearLayout>
The issue I am facing looks like this -
I want the image to be able to move on top of the buttons when touching it, but also of course for the buttons to be touchable and functional.
Here is my TinderStackLayout class -
public class TinderStackLayout extends FrameLayout {
// Constants
private static final int DURATION = 300;
// Variable members
private OnCardSwipedListener onCardSwipedListener;
private int screenWidth;
private int yMultiplier;
//Top card
private TinderCardView topCardOnStack;
private Button mDeleteButton, mPassButton, mApproveButton;
//Constructors
public TinderStackLayout(Context context) {
super(context);
init();
}
public TinderStackLayout(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public TinderStackLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
#Override
public void addView(View child, int index, ViewGroup.LayoutParams params) {
super.addView(child, index, params);
if (onCardSwipedListener != null)
onCardSwipedListener.onNext(getChildCount());
}
#Override
public void removeView(View view) {
super.removeView(view);
if (onCardSwipedListener != null)
onCardSwipedListener.onNext(getChildCount());
}
#Override
public void onDetachedFromWindow() {
super.onDetachedFromWindow();
}
// Helper Methods
private void init() {
setClipChildren(false);
screenWidth = DisplayUtility.getScreenWidth(getContext());
yMultiplier = DisplayUtility.dp2px(getContext(), 8);
mDeleteButton = new Button(getContext());
mPassButton = new Button(getContext());
mApproveButton = new Button(getContext());
}
public void addCard(TinderCardView tinderCardView) {
View firstCard = getChildAt(0);
if (firstCard != null && firstCard.equals(tinderCardView)) {
return;
}
if (onCardSwipedListener == null)
onCardSwipedListener = tinderCardView.getOnCardSwipedListener();
topCardOnStack = tinderCardView;
ViewGroup.LayoutParams layoutParams;
layoutParams = new ViewGroup.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT);
int childCount = getChildCount();
addView(tinderCardView, 0, layoutParams);
float scaleValue = 1 - (childCount / 50.0f);
tinderCardView.animate()
.x(0)
.y(childCount * yMultiplier)
.scaleX(scaleValue)
.setInterpolator(new AnticipateOvershootInterpolator())
.setDuration(DURATION);
}
public TinderCardView getTopCardOnStack() {
return topCardOnStack;
}
}
Do I need to add them dynamically? or is there a simpler way?
And if I do need to add them dynamically - I would be happy to get a code example of how to do so.
Related
I have a general layout for my app in place, which includes a horizontal scroll view.
What I'm doing is adding 32 fragments to the scroll view (which inflates into a vertical linear layout with two buttons and an editText. They're going to be controls for an equalizer).
The problem is, when I try to edit one of the editText's, the scrollview scrolls all the way to the right - so you're unable to see what you're typing into, and have to scroll all the way back to that entry to view it.
Here's the main xml layout. It splits the screen up into 4 quadrants, with the horizontal scroll view going in the bottom right:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout 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"
android:orientation="horizontal"
tools:context=".MainActivity"
android:focusable="true"
android:focusableInTouchMode="true">
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:padding="4dp"
android:orientation="vertical"
android:layout_weight="2"
>
<TextView android:text="Hello World!" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
</LinearLayout>
<LinearLayout
android:layout_width="0dp"
android:layout_height="fill_parent"
android:layout_weight="4"
android:padding="4dp"
android:orientation="vertical"
android:background="#FF0000"
>
<TextView android:text="Hello World!" android:layout_width="wrap_content"
android:layout_height="wrap_content" />
<HorizontalScrollView
android:id="#+id/hsv_eqControls"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:padding="2dp"
android:background="#FFFFFF"
android:descendantFocusability="beforeDescendants"
android:focusable="true"
android:focusableInTouchMode="true"
>
<LinearLayout
android:id="#+id/layout_eqControls"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="horizontal">
</LinearLayout>
</HorizontalScrollView>
</LinearLayout>
</LinearLayout>
And this is what I'm adding into the scrollview
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:padding="3dp"
android:orientation="vertical">
<Button
android:id="#+id/btn_eqUp"
android:layout_width="60dp"
android:layout_height="60dp" />
<EditText
android:id="#+id/etext_eq"
android:layout_width="60dp"
android:layout_height="wrap_content"
android:inputType="numberDecimal|numberSigned"
android:textAlignment="center"
android:layout_gravity="center_horizontal"
android:background="#EEEEEE"
android:hint="32dB"/>
<Button
android:id="#+id/btn_eqDown"
android:layout_width="60dp"
android:layout_height="60dp" />
<TextView
android:id="#+id/vtext_eqLabel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textAlignment="center"
android:layout_gravity="center"
android:text="1"/>
</LinearLayout>
This is the code I'm running to fill the scrollview:
public class MainActivity extends AppCompatActivity {
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
// View eqControls = findViewById(R.id.hsv_eqControls);
FragmentTransaction ft = getFragmentManager().beginTransaction();
for(int i = 1; i < 33; i++)
{
ft.add(R.id.layout_eqControls, new FragmentEQ(), "ch"+i);
}
ft.commit();
getFragmentManager().executePendingTransactions();
for(int i = 1; i < 33; i++)
{
FragmentEQ feq = (FragmentEQ) getFragmentManager().findFragmentByTag("ch"+i);
if(feq != null)
feq.setChannel(i);
}
}
}
And this is the code for my fragment:
public class FragmentEQ extends Fragment {
protected int _channel = 0;
protected ViewGroup _parent;
#Override
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState)
{
// Inflate the layout for this fragment
View view = inflater.inflate(R.layout.activity_fragment_eq, container, false);
TextView label = (TextView) view.findViewById(R.id.vtext_eqLabel);
label.setText(Integer.toString(_channel));
return view;
}
public int getChannel() { return _channel; }
public void setChannel(int i)
{
_channel = i;
}
}
I've tried creating a custom HorizontalScrollView, and overriding scrollTo() and onRequestFocusInDescendants() as blank methods that do nothing, but this changes nothing.
public class EQScrollView extends HorizontalScrollView {
public EQScrollView( Context context, AttributeSet attrs)
{
super(context, attrs);
setSmoothScrollingEnabled(false);
}
#Override
public void scrollTo(int x, int y)
{
}
#Override
public boolean onRequestFocusInDescendants(int x, Rect y)
{
return false;
}
}
Using "setRawInputType":
setRawInputType(InputType.TYPE_CLASS_NUMBER);
solved the issue for me at first. After realizing that some number keyboards don't provide decimal input I ended up using standard text input for EditText, extending HorizontalScrollView and overriding "onRequestFocusInDescendants", "requestChildRectangleOnScreen" and "getFocusables" like so:
public class HorizontalScrollViewEx extends HorizontalScrollView {
public HorizontalScrollViewEx(Context context) {
super(context);
}
public HorizontalScrollViewEx(Context context, AttributeSet attrs) {
super(context, attrs);
}
public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public HorizontalScrollViewEx(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
protected boolean onRequestFocusInDescendants(int direction, Rect previouslyFocusedRect) {
return true;
}
#Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
return true;
}
#Override
public ArrayList<View> getFocusables(int direction) {
return new ArrayList<View>();
}
}
I have just encountered this problem and for me the scrolling to the end only happens when android:inputType is not set in the EditText. If you remove this then the issue should vanish.
FYI even using .setInputType(InputType.TYPE_CLASS_NUMBER); produces this error.
Admittedly this isn't a fix but it's worth noting the cause.
HorizontalScrollView always scroll to the right when I try to click the EditText
I have fixed the similar by the way below:
In my scenario
<HorizontalScrollView
android:id="#+id/id_HorizontalScrollView"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#drawable/border_left_black_bold">
<android.support.v7.widget.RecyclerView
android:id="#+id/id_RecyclerView"
android:layout_width="match_parent"
android:layout_height="match_parent"/>
</HorizontalScrollView>
RecyclerView's item view:
<LinearLayout>
<EditText
android:id="#+id/id_edit"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:background="#drawable/border_right_black"
android:gravity="center"
android:inputType="number" />
<LinearLayout/>
Solution in my way:
Customize HorizontalScrollView and override the requestChildRectangleOnScreen method
#Override
public boolean requestChildRectangleOnScreen(View child, Rect rectangle, boolean immediate) {
return true;
}
#Override
protected int computeScrollDeltaToGetChildRectOnScreen(Rect rect) {
return 0;
}
root causes
Let's back to the Android source code.
when the soft keyboard pop up. the size of layout changed View.java protected void onLayout(boolean changed, int left, int top, int right, int bottom)
/**
* Called from layout when this view should
* assign a size and position to each of its children.
* ....
*/
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
}
Then HorizontalScrollView.java protected void onLayout(boolean changed, int left, int top, int right, int bottom)
In this method, mIsLayoutDirty = false;
HorizontalScrollView.java public void requestChildFocus(View child, View focused)
HorizontalScrollView.java private void scrollToChild(View child)
HorizontalScrollView.java
int scrollDelta = computeScrollDeltaToGetChildRectOnScreen(mTempRect);
if(scrollDelta!=0){
scrollBy(scrollDelta, 0);
}
I am trying to make a composite view by extending RelativeLayout It consists of three widgets. An ImageView , a ProgressBar and a TextView . But for some reason I am unable to see the ImageView and TextView. Attaching code below. Any suggestions?
public class ProgressView extends RelativeLayout {
#InjectView(R.id.ivItemPic)
ImageView ivItemPic;
#InjectView(R.id.tvMessage)
TextView tvMessage;
#InjectView(R.id.pbLoading)
ProgressBar pbLoading;
int defColor = 0xff669900;
public ProgressView(Context context) {
super(context);
init(context,null, 0);
}
public ProgressView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context,attrs, 0);
}
public ProgressView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context,attrs, defStyle);
}
public void init(Context context, AttributeSet attrs, int defStyleAttr) {
inflate(context, R.layout.component_progress_view, this);
ButterKnife.inject(this);
TypedArray aTypedArray = context.obtainStyledAttributes(attrs, R.styleable.ProgressView, defStyleAttr, 0);
final int textSize = aTypedArray.getDimensionPixelSize(
R.styleable.ProgressView_pvTextSize,
dipsToPix(R.dimen.font_medium));
final int textColor = aTypedArray.getColor(R.styleable.ProgressView_pvTextColor,defColor);
final Drawable imgSrc = aTypedArray.getDrawable(R.styleable.ProgressView_pvImageSrc);
ivItemPic.setImageDrawable(imgSrc);
tvMessage.setTextSize(textSize);
tvMessage.setTextColor(textColor);
aTypedArray.recycle();
}
/**
* Helper method to convert dips to pixels.
*/
private int dipsToPix(float dps) {
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dps,
getResources().getDisplayMetrics());
}
public void setText(String message) {
tvMessage.setText(message);
}
public void imageVisibility(boolean visible) {
ivItemPic.setVisibility(visible ? VISIBLE : GONE);
}
public void progressIndeterminate(boolean indeterminate) {
pbLoading.setIndeterminate(indeterminate);
}
public void setItemImage(Drawable drawable) {
ivItemPic.setImageDrawable(drawable);
}
public void setItemImageRes(int res) {
ivItemPic.setImageResource(res);
}
The XML
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent" android:layout_height="match_parent">
<ImageView
android:id="#+id/ivItemPic"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="#+id/pbLoading"
android:layout_centerHorizontal="true"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:src="#drawable/ic_action_info"/>
<ProgressBar
android:id="#+id/pbLoading"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginBottom="#dimen/activity_vertical_margin"
android:layout_centerInParent="true"
style="?android:attr/progressBarStyleHorizontal"
android:indeterminate="true"
android:visibility="visible" />
<TextView
android:id="#+id/tvMessage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_below="#+id/pbLoading"
android:layout_marginTop="#dimen/activity_vertical_margin"
android:layout_marginRight="#dimen/horizontal_margin"
android:layout_marginLeft="#dimen/horizontal_margin"
android:textSize="#dimen/font_medium"
android:textColor="#color/grey_normal"
android:gravity="center"
android:text="Message"/>
The Layout
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
xmlns:errorview="http://schemas.android.com/apk/res-auto"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#color/background_color"
tools:context="com.mobility.ui.SyncFragment">
<com.mobility.customviews.SuccessView
android:id="#+id/svSuccess"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="visible"
android:gravity="center"
app:svText="Success"
app:svTextColor="#android:color/holo_green_dark"/>
<tr.xip.errorview.ErrorView
android:id="#+id/evError"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
errorview:ev_errorSubtitle="#string/err_conn"
errorview:ev_errorTitle="#string/oops"
errorview:ev_showRetryButton="true"
errorview:ev_showSubtitle="true"
errorview:ev_showTitle="true"
android:gravity="center"
android:visibility="gone"
android:paddingLeft="#dimen/horizontal_margin"
android:paddingRight="#dimen/horizontal_margin"
errorview:ev_retryButtonTextColor="#color/error_retry"/>
<com.mobility.customviews.ProgressView
android:id="#+id/progressView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:pvText="ZzZZ"/>
I want to get a View from xml file to normal class, I used the LayoutInflater, but it gives me only copy of this view instead of original (I would like to set changes to elements).
Is that possible to get original the layout from xml? How can I fix it?
Class in which I want to get layout
public class Board {
private Context context;
private View inflated;
private RelativeLayout screen;
public Board(Context context) {
LayoutInflater inflater = (LayoutInflater) context.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
inflated = inflater.inflate(R.layout.board, null);
screen = (RelativeLayout) inflated.findViewById(R.id.custom_board_screen);
this.context = context;
}
public TrippleToggleButton getButton(int id) {
//return (TrippleToggleButton) inflated.findViewById(id);
TrippleToggleButton btn;
for(int i=0;i<screen.getChildCount();i++)
{
View v1 = screen.getChildAt(i);
if(v1 instanceof TableLayout)
{
for(int j=0;j<((TableLayout) v1).getChildCount();j++)
{
View v2 = ((TableLayout) v1).getChildAt(j);
if (v2 instanceof TableRow)
{
for(int k=0;k<((TableRow) v2).getChildCount();k++)
{
View v3 = ((TableRow) v2).getChildAt(k);
if (v3 instanceof TrippleToggleButton)
{
Log.i("2014.07.10",screen.getId()+" ; "+v3.getId());
//originally id of button are 0-8; inflated 9 - 17
if (v3.getId()==id) return (TrippleToggleButton)v3;
}
}
}
}
}
}
return null;
}
}
Xml file:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/custom_board_screen"
android:layout_width="match_parent"
android:layout_height="match_parent">
<TableLayout
android:id="#+id/custom_board_table"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true">
<TableRow
android:id="#+id/custom_board_table_row1"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<View style="#style/DividingHorizontalLine"/>
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<board.TrippleToggleButton
/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff000000">
<View style="#style/DividingHorizontalLine"/>
</TableRow>
<TableRow
android:id="#+id/custom_board_table_row2"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<View style="#style/DividingHorizontalLine"/>
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<board.TrippleToggleButton
/>
</TableRow>
<TableRow
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ff000000">
<View style="#style/DividingHorizontalLine"/>
</TableRow>
<TableRow
android:id="#+id/custom_board_table_row3"
android:layout_width="wrap_content"
android:layout_height="wrap_content">
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<View style="#style/DividingHorizontalLine"/>
<board.TrippleToggleButton
/>
<View style="#style/DividingVerticalLine"/>
<board.TrippleToggleButton
/>
</TableRow>
</TableLayout>
</RelativeLayout>
My custom button class:
public class TrippleToggleButton extends Button implements View.OnClickListener {
private Sign actual_state;
private final float scale = getContext().getResources().getDisplayMetrics().density;
private int dps = 50;
private int pixels = (int) (dps * scale + 0.5f);
private static int buttonCount = 0;
public TrippleToggleButton(Context context) {
this(context, null);
}
public TrippleToggleButton(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public TrippleToggleButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
addFeatures();
}
private void addFeatures() {
actual_state = Sign.UNCHECKED;
setOnClickListener(this);
ViewGroup.LayoutParams param = new ViewGroup.LayoutParams(pixels, pixels);
setLayoutParams(param);
setGravity(Gravity.CENTER_HORIZONTAL | Gravity.CENTER_VERTICAL);
setMinimumHeight(pixels);
setMinimumWidth(pixels);
setMinHeight(pixels * 2);
setMinWidth(pixels * 2);
setPadding(pixels / 10, pixels / 10, pixels / 10, pixels / 10);
setTextSize(pixels);
setId(IDAllocator.getNextID()); // this is just a static method which sets ID's starting from 0
}
private void onUncheckedState() {
}
public Sign getActual_state() {
return actual_state;
}
public boolean isUnchecked() {
return getActual_state() == Sign.UNCHECKED;
}
public void setState(Sign newState) {
actual_state = newState;
setText(actual_state.toString());
setClickable(false);
}
#Override
public void onClick(View v) {
TrippleToggleButton btn = (TrippleToggleButton) v;
if (btn.isUnchecked()) {
Toast t = Toast.makeText(getContext(),""+getId(),Toast.LENGTH_SHORT); // it shows correct ID, everything goes ok here
t.show();
Container.performAction(btn);
}
}
}
There is no "original" from the xml's perspective. The xml describes a layout, it isn't literally a layout hierarchy. Whenever you inflate an xml, the inflater uses the xml as a guide to build a new layout hierarchy, which you get a reference to. If you want to update that original inflated view, pass that original reference to your Board class and perform the changes there rather than inflating the entire thing again.
I am having trouble in getting the GridView content height programmatically since I am placing it inside a ScrollView, I just need to stretch the GridView height dynamically by getting its content height in PIXELS. Here's what I did:
#Override
public void onWindowFocusChanged(boolean hasFocus)
{
// TODO Auto-generated method stub
super.onWindowFocusChanged(hasFocus);
System.out.println("...111Height..."+gridView.getMeasuredWidth());
}
but I want to obtain the value inside OnCreate so that I can feed it to layoutParams.height in:
GridView gridView = (GridView) findViewById(R.id.gridview_module);
ViewGroup.LayoutParams layoutParams = gridView.getLayoutParams();
layoutParams.height = convertDpToPixels(iDontKnowWhatToPutHere, this);
gridView.setLayoutParams(layoutParams);
and the method to convert from pixels to dp:
public static int convertDpToPixels(float dp, Context context) {
Resources resources = context.getResources();
return (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP, dp,
resources.getDisplayMetrics());
}
EDIT:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="#+id/mainLayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:paddingBottom="#dimen/activity_vertical_margin"
android:paddingLeft="#dimen/activity_horizontal_margin"
android:paddingRight="#dimen/activity_horizontal_margin"
android:paddingTop="#dimen/activity_vertical_margin"
tools:context=".SecondActivity" >
<ScrollView
android:id="#+id/scrollview"
android:layout_width="match_parent"
android:layout_height="0"
android:layout_weight="1"
android:fillViewport="true"
android:scrollbars="none" >
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="#+id/tv"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="#string/hello_world" />
<com.example.ExpandableHeightGridView
android:id="#+id/gridview_module"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_below="#id/tv"
android:layout_weight="1"
android:gravity="center"
android:horizontalSpacing="20dp"
android:numColumns="3"
android:stretchMode="columnWidth"
android:verticalSpacing="10dp" />
<Button
android:id="#+id/dial_phone"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_below="#id/gridview_module"
android:onClick="dialPhone"
android:text="Dial Phone" />
</LinearLayout>
</ScrollView>
To achieve this you need to create CustomGridview like this
public class CustomGridView extends GridView {
private int old_count;
private android.view.ViewGroup.LayoutParams params;
private boolean isExpandFully = false;
private int verticleSpacing = 4;
private int noOfCollumns = 1;
public int getNumColumns() {
return noOfCollumns;
}
public void setNoOfCollumns(int noOfCollumns) {
this.noOfCollumns = noOfCollumns;
}
public int getVerticleSpacing() {
return verticleSpacing;
}
public void setVerticleSpacing(int verticleSpacing) {
this.verticleSpacing = verticleSpacing;
}
public void setExpandFully(boolean isExpandFully) {
this.isExpandFully = isExpandFully;
}
public CustomGridView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public CustomGridView(Context context, AttributeSet attrs) {
super(context, attrs);
init(attrs);
}
public CustomGridView(Context context) {
super(context);
init(null);
}
private void init(AttributeSet attrs) {
if (attrs != null) {
String namespace = "http://schemas.android.com/apk/res/android";
noOfCollumns = attrs.getAttributeIntValue(namespace, "numColumns", 1);
}
}
#Override
protected void onDraw(Canvas canvas) {
setVerticalSpacing(getVerticleSpacing());
if (isExpandFully) {
try {
if (getCount() != old_count) {
old_count = getCount();
params = getLayoutParams();
int len = (getCount() % getNumColumns() == 0 ? getCount() / getNumColumns() : getCount() / getNumColumns() + 1);
params.height = 0;
for (int i = 0; i < len; i++) {
params.height = params.height + (old_count > 0 ? getChildAt(0).getHeight() + getVerticleSpacing() : 0);
}
params.height += 10;
setLayoutParams(params);
}
} catch (Exception e) {
}
}
super.onDraw(canvas);
}
}
how to use
CustomGridView myGridview = (CustomGridView)findViewById(R.id.customGridview);
myGridview.setExpandFully(true);
I want to create a ViewGroup that contains unknown number of other views as children (like LinearLayout):
<Wizard id=... width=... height=...>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
<LinearLayout ...>
...
</LinearLayout>
</WIzardStep>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
<RelativeLayout ...>
...
</RelativeLayout>
</WIzardStep>
<WizardStep id=... nextButtonOnClick=... preButtonOnClick=... >
...
</WIzardStep>
</Wizard>
Here Wizard and WizardStep both are ViewGroup. I don't have clue where to start. Extending ViewGroup and required functionality is all I need to do? I will appreciate any help, document, blog, etc.
This can be achieved through a ViewFlipper. If you wanted to do it programmatically, this would be a start. (NOTE: I didn't test this code, just wrote it off the top of my head)
The xml layout flip.xml
<?xml version="1.0" encoding="utf-8"?>
<ViewFlipper xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/flippy"
android:layout_width="match_parent"
android:layout_height="match_parent" >
</ViewFlipper>
And the activity would look something like this
public class MainActivity extends Activity{
ViewFlipper flip;
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.flip);
flip = (ViewFlipper)findViewById(R.id.flip);
}
private void addViews(){
//This is where you would determine which views to add
flip.add(****** your view 1 *****)
flip.add(****** your view 2 *****)
}
You would add views whenever you were parsing the data to create them dynamically.
Then to navigate your views you can use:
flip.showNext()
flip.showPrevious()
There are more complicated things you can do with it, but that should give you the basics.
My Solution:
WizardView class:
public class WizardView extends RelativeLayout {
Context context;
private final String KEY_LAST_STEP_PASSED = "KEY_LAST_STEP_PASSED";
private final String KEY_WIZARD_FINISHED = "KEY_WIZARD_FINISHED";
private int currentStep;
private boolean isWizardFinished;
private SharedPreferences preferences;
public WizardView(Context context) {
super(context);
this.context = context;
}
public WizardView(Context context, AttributeSet attrs) {
super(context, attrs);
this.context = context;
}
public WizardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
this.context = context;
}
public void startWizard() {
preferences = context.getSharedPreferences("wizard_pref", Context.MODE_PRIVATE);
isWizardFinished = preferences.getBoolean(KEY_WIZARD_FINISHED, false);
if (!isWizardFinished) {
currentStep = preferences.getInt(KEY_LAST_STEP_PASSED, 0);
// Make all Steps (except current step) GONE
int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (currentStep == i) {
child.setVisibility(View.VISIBLE);
} else {
child.setVisibility(View.GONE);
}
}
}
}
public void nextStep() {
int count = getChildCount();
getChildAt(currentStep).setVisibility(View.GONE);
if (currentStep < (count - 1)) {
currentStep++;
preferences.edit().putInt(KEY_LAST_STEP_PASSED, currentStep).commit();
getChildAt(currentStep).setVisibility(View.VISIBLE);
} else {
finishWizard();
}
}
public void previousStep() {
if (currentStep > 0) {
getChildAt(currentStep).setVisibility(View.GONE);
currentStep--;
preferences.edit().putInt(KEY_LAST_STEP_PASSED, currentStep).commit();
getChildAt(currentStep).setVisibility(View.VISIBLE);
}
}
public void finishWizard() {
isWizardFinished = true;
preferences.edit().putBoolean(KEY_WIZARD_FINISHED, true).commit();
setVisibility(View.GONE);
}
}
WizardStep Class:
public class WizardStepView extends RelativeLayout {
public WizardStepView(Context context) {
super(context);
}
public WizardStepView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public WizardStepView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
}
Sample layout file with Wizard:
<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" >
<com.example.wizardtest.WizardView
android:id="#+id/wizard"
android:layout_width="match_parent"
android:layout_height="match_parent" >
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Next(2)" />
</com.example.wizardtest.WizardStepView>
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Next(3)" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="wizardPrevious"
android:text="Previous(1)" />
</com.example.wizardtest.WizardStepView>
<com.example.wizardtest.WizardStepView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:visibility="gone" >
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentLeft="true"
android:onClick="wizardPrevious"
android:text="Previous(2)" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentRight="true"
android:onClick="wizardNext"
android:text="Finish" />
</com.example.wizardtest.WizardStepView>
</com.example.wizardtest.WizardView>
</RelativeLayout>
Activity:
WizardView wizardView;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
wizardView = (WizardView) findViewById(R.id.wizard);
wizardView.startWizard();
}