I'm trying to create custom layout "SquareBox" based on relative layout to hold a ImageView in center.
And this custom layout will always be in square size (depend on ImageView's height and width).
protected void onMeasure(int width, int height) {
super.onMeasure(width, height);
int measuredWidth = getMeasuredWidth();
int measuredHeight = getMeasuredHeight();
int size;
if (measuredWidth > measuredHeight) {
size = measuredWidth;
} else {
size = measuredHeight;
}
setMeasuredDimension(size, size);
}
Here is my layout code:
<com.example.tools.SquareBox
android:id="#+id/square_box"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/canvas_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
tools:src="#drawable/demo_image" />
</com.example.tools.SquareBox>
It is working fine but the image-view is not in center of this custom view.
I've tried following:
->android:layout_centerInParent="true" for ImageView.
->android:gravity="center" for "SquareBox".
->Adding CENTER_IN_PARENT programmatically to ImageView in SquareBox's onMeasure method.
But nothing is working.
What am i missing here?
Change your layout to this (change layout_width to match_parent) :
<com.example.tools.SquareBox
android:id="#+id/square_box"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:background="#android:color/darker_gray">
<ImageView
android:id="#+id/canvas_image"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_margin="0dp"
android:layout_centerInParent="true"
android:adjustViewBounds="true"
android:scaleType="fitCenter"
tools:src="#drawable/demo_image" />
</com.example.tools.SquareBox>
And change your custom layout to this:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
int size;
if(widthMode == MeasureSpec.EXACTLY && widthSize > 0){
size = widthSize;
}
else if(heightMode == MeasureSpec.EXACTLY && heightSize > 0){
size = heightSize;
}
else{
size = widthSize < heightSize ? widthSize : heightSize;
}
int finalMeasureSpec = MeasureSpec.makeMeasureSpec(size, MeasureSpec.EXACTLY);
super.onMeasure(finalMeasureSpec, finalMeasureSpec);
}
Try this:-android:layout_gravity="center_horizontal"
I have emulated the square box behavior in another way. I think it's a workaround and It may be not the best solution but it works. I would like to know better and cleaner solution.
Layout File:
<?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="vertical">
<RelativeLayout
android:id="#+id/square_box_holder"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_margin="0dp"
android:layout_weight="3">
<View
android:id="#+id/square_box"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_centerInParent="true"
android:background="#android:color/darker_gray" />
<ImageView
android:id="#+id/canvas_image"
style="#style/CanvasImageStyle"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerInParent="true"
android:layout_margin="0dp"
android:adjustViewBounds="true"
tools:src="#drawable/demo_image2" />
</RelativeLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1">
</LinearLayout>
</LinearLayout>
Code to resize the view:
squareImageView.setImageBitmap(getResultBitmap());
squareBoxHolder.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
squareBoxHolder.getViewTreeObserver().removeOnPreDrawListener(this);
Log.i(TAG, "onPreDraw: squareBoxHolder");
squareBoxHolderSize = new Point(squareBoxHolder.getMeasuredWidth(), squareBoxHolder.getMeasuredHeight());
return true;
}
});
squareImageView.getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() {
#Override
public boolean onPreDraw() {
squareImageView.getViewTreeObserver().removeOnPreDrawListener(this);
Log.i(TAG, "onPreDraw: squareImageView");
int imageWidth = squareImageView.getMeasuredWidth();
int imageHeight = squareImageView.getMeasuredHeight();
int size;
ViewGroup.LayoutParams layoutParams = squareImageView.getLayoutParams();
if (imageWidth > imageHeight) {
if (imageWidth > squareBoxHolderSize.y) {
size = squareBoxHolderSize.y;
layoutParams.width = size;
squareImageView.setLayoutParams(layoutParams);
} else {
size = imageWidth;
}
} else {
if (imageHeight > squareBoxHolderSize.x) {
size = squareBoxHolderSize.x;
layoutParams.height = size;
squareImageView.setLayoutParams(layoutParams);
} else {
size = imageHeight;
}
}
layoutParams = squareBox.getLayoutParams();
layoutParams.height = size;
layoutParams.width = size;
squareBox.setLayoutParams(layoutParams);
return true;
}
});
Related
I have this custom view:
public class TopBarHandler extends FrameLayout {
private Drawable mRightButtonSrc;
private boolean mShowRightButton;
private String mTitle;
private ImageButton mHamburgerButton;
private EllipsizingTextView mTitleTextView;
private ImageButton mRightButton;
private ProgressBar mProgressBar;
public TopBarHandler(final Context context, final AttributeSet attrs) {
super(context, attrs);
initView();
TypedArray a = getContext().obtainStyledAttributes(attrs, R.styleable.topbarMenu);
mShowRightButton = a.getBoolean(R.styleable.topbarMenu_showRightButton, false);
mRightButtonSrc = a.getDrawable(R.styleable.topbarMenu_rightButtonSrc);
mTitle = a.getString(R.styleable.topbarMenu_titleText);
}
public TopBarHandler(final Context context) {
super(context);
initView();
}
private void initView() {
View view = inflate(getContext(), R.layout.top_bar_layout, null);
mHamburgerButton = (ImageButton) findViewById(R.id.top_bar_hamburger_button);
mTitleTextView = (EllipsizingTextView) findViewById(R.id.top_bar_title);
mRightButton = (ImageButton) findViewById(R.id.top_bar_right_button);
mProgressBar = (ProgressBar) findViewById(R.id.top_bar_progress_bar);
addView(view);
}
public interface TopBarListener {
void onHamburgerButtonPressed();
void onRightButtonPressed();
}
}
With this layout definition:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="#+id/top_bar_layout"
android:layout_width="match_parent"
android:layout_height="#dimen/height_top_bar"
android:background="#drawable/gradient_top_bar"
android:gravity="center_vertical">
<ImageButton
android:id="#+id/top_bar_hamburger_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_centerVertical="true"
android:layout_marginLeft="#dimen/margin_objects_top_bar"
android:src="#drawable/selector_menu_topbar"
android:background="#null"/>
<com.myproject.android.utilities.fonts.EllipsizingTextView
android:id="#+id/top_bar_title"
style="#style/bar_title_style"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerVertical="true"
android:text="#string/CameraWizard_CameraWizard"
android:textSize="#dimen/menu_top_bar_title_size"
android:layout_marginLeft="#dimen/margin_top_bar_title"
android:layout_toLeftOf="#+id/top_bar_right_button"
android:layout_alignParentLeft="true"/>
<ImageButton
android:id="#+id/top_bar_right_button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="#dimen/margin_objects_top_bar"
android:background="#drawable/top_bar_search"
android:visibility="invisible" />
<ProgressBar
android:id="#+id/top_bar_progress_bar"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:layout_centerVertical="true"
android:layout_marginRight="#dimen/margin_objects_top_bar"
android:indeterminate="false"
android:minHeight="50dp"
android:minWidth="50dp"
android:progress="1"
android:visibility="gone" />
</RelativeLayout>
And I want to put it in multiple layouts, so I do it like this:
<com.myproject.android.menu.TopBarHandler
android:layout_height="#dimen/height_top_bar"
android:layout_width="fill_parent"
/>
But the thing is, if I want to put this in multiple layouts (70+) then I have to specify the height and width in every single one of them. Is there a way to enforce the height in the customview itself?
If I dont specify height and width on the target layout, then I get an error. If I put wrap_content the height specified in the topbar_layout is ignored.
You need to implement onMeasure() in your custom view:
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
// What is the desired size of the view?
int desiredWidth = 250;
int desiredHeight = 250;
// The MeasureSpecs passed in will depend on the LayoutParams
// applied to the view in xml or programmatically
// Analyse the MeasureSpec for width and height separately like this:
int widthMode = MeasureSpec.getMode(widthMeasureSpec);
int widthSize = MeasureSpec.getSize(widthMeasureSpec);
switch (widthMode) {
case MeasureSpec.UNSPECIFIED:
widthSize = desiredWidth;
break;
case MeasureSpec.AT_MOST:
widthSize = Math.min(widthSize, desiredWidth);
break;
case MeasureSpec.EXACTLY:
break;
default:
}
int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
switch (heightMode) {
case MeasureSpec.UNSPECIFIED:
heightSize = desiredHeight;
break;
case MeasureSpec.AT_MOST:
heightSize = Math.min(heightSize, desiredHeight);
break;
case MeasureSpec.EXACTLY:
break;
default:
}
// You must call setMeasuredDimension()
setMeasuredDimension(widthSize, heightSize);
}
i have customlistview.i successfully added footerView in my listview.this is a source
void loadDataLastTransactions(int limit) {
footerView = getActivity().getLayoutInflater().
inflate(R.layout.listview_footer_layout, null);
if (cashTransactionlist.size() <= limit) {
transactionAdapter = new TransactionAdapter(getActivity(), cashTransactionlist);
} else {
List<Transaction> sixTramsactions = cashTransactionlist.subList(0, limit);
transactionAdapter = new TransactionAdapter(getActivity(), sixTramsactions);
}
transactionsList.addFooterView(footerView, null, false);
transactionsList.setAdapter(transactionAdapter);
}
this is a my footerView's xml code
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingTop="7dip"
android:paddingBottom="7dip"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical|left"
>
<LinearLayout
android:id="#+id/footer_layout"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
>
<TextView
android:id="#+id/u_transaction_view_all"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:textColor="#color/u_blue"
android:textSize="#dimen/u_common_text_size"
android:text="#string/u_transaction_view_all"
android:padding="8dp"
/>
</LinearLayout>
</LinearLayout>
my footerView's xml looks like a pic
this is a my mainactivity.xml code
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#f2f2f2"
android:id="#+id/dashboard_main_layout"
android:clickable="true"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical|left"
>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:background="#ffffff"
android:orientation="vertical">
<LinearLayout
android:id="#+id/u_dashboard_expandable_container"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#d9d9d9"/>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<GridView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:numColumns="3"
android:stretchMode="columnWidth"
android:id="#+id/dashboard_header_gridview" />
<View
android:layout_width="match_parent"
android:background="#ffffff"
android:layout_height="match_parent"
android:layout_marginLeft="-1dp"/>
</LinearLayout>
</LinearLayout>
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#d9d9d9"/>
<ScrollView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical|left">
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:background="#d9d9d9"/>
<LinearLayout
android:id="#+id/fragments_transaction_list_layout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_below="#+id/fragments_cardview"
android:orientation="vertical"
android:layout_gravity="center_horizontal"
android:gravity="center_vertical|left"
>
<android.custom.CustomListview
android:id="#+id/u_transaction_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:animationCache="false"
android:cacheColorHint="#00000000"
android:clipToPadding="false"
android:divider="#null"
android:dividerHeight="0dp"
android:listSelector="#00000000"
android:scrollbars="none"
android:scrollingCache="false"
android:smoothScrollbar="true" >
</android.custom.CustomListview>
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
public class CustomListview extends ListView implements View.OnTouchListener, OnScrollListener {
private int listViewTouchAction;
private static final int MAXIMUM_LIST_ITEMS_VIEWABLE = 99;
public CustomListview(Context context, AttributeSet attrs) {
super(context, attrs);
listViewTouchAction = -1;
setOnScrollListener(this);
setOnTouchListener(this);
}
#Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, -1);
}
}
}
#Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
int newHeight = 0;
final int heightMode = MeasureSpec.getMode(heightMeasureSpec);
int heightSize = MeasureSpec.getSize(heightMeasureSpec);
if (heightMode != MeasureSpec.EXACTLY) {
ListAdapter listAdapter = getAdapter();
if (listAdapter != null && !listAdapter.isEmpty()) {
int listPosition = 0;
for (listPosition = 0; listPosition < listAdapter.getCount()
&& listPosition < MAXIMUM_LIST_ITEMS_VIEWABLE; listPosition++) {
View listItem = listAdapter.getView(listPosition, null, this);
if (listItem instanceof ViewGroup) {
listItem.setLayoutParams(new LayoutParams(
LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
}
listItem.measure(widthMeasureSpec, heightMeasureSpec);
newHeight += listItem.getMeasuredHeight();
}
newHeight += getDividerHeight() * listPosition;
}
if ((heightMode == MeasureSpec.AT_MOST) && (newHeight > heightSize)) {
if (newHeight > heightSize) {
newHeight = heightSize;
}
}
} else {
newHeight = getMeasuredHeight();
}
setMeasuredDimension(getMeasuredWidth(), newHeight);
}
#Override
public boolean onTouch(View v, MotionEvent event) {
if (getAdapter() != null && getAdapter().getCount() > MAXIMUM_LIST_ITEMS_VIEWABLE) {
if (listViewTouchAction == MotionEvent.ACTION_MOVE) {
scrollBy(0, 1);
}
}
return false;
}
}
when i run my app my footer view is left possition.in my option i have problem in activity_main.xml file because footerView's xml is correct.what is a wrong if anyone knows solution please help me
thanks everyone
Property layout_gravity affects an element aligning it relative to its parent, while gravity property aligns child views of that view. Example:
If you apply
android:gravity="center"
android:layout_gravity="left"
to a TextView it means that TextView container will be aligned left and the text inside will be centered.
Catch 22:
When you add your footer layout to ListView, it may have a RelativeLayout parent, and RelativeLayout does not support the layout_gravity property. In that case, fix would be to add:
layout_centerHorizontal="true"
layout_alignParentBottom="true"
to the root of your footer layout.
I'm trying to create a to-do list just like "google keep" android app.
Basically, I need a scrolled layout with 2 lists: one of the checked items, and one of the unchecked ones.
The unchecked list should have an option to drag & drop the items in order to change their position.
My only problem is that I can't use width=wrap_content in recyclerview, and the layoutManager implementation that I found make the app crash when I try to drag & drop.
For the drag & drop I use this library.
My layout:
<ScrollView
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:fillViewport="true"
tools:context="views.fragments.ItemsFragment">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<AutoCompleteTextView
android:id="#+id/fragment_items_atv_name"
android:layout_width="0dp"
android:layout_weight="1"
android:layout_height="wrap_content" />
<Button
android:id="#+id/fragment_items_btn_add"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:padding="8dp"
android:text="#string/add" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<android.support.v7.widget.RecyclerView
android:id="#+id/fragment_items_lv_unchecked_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<android.support.v7.widget.RecyclerView
android:id="#+id/fragment_items_lv_checked_list"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<TextView
android:id="#+id/fragment_items_tv_empty"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Empty list"
android:visibility="gone" />
</LinearLayout>
</LinearLayout>
</ScrollView>
The layout manager I use
public class MyLinearLayoutManager extends LinearLayoutManager {
public MyLinearLayoutManager(Context context) {
super(context, VERTICAL, false);
}
private int[] mMeasuredDimension = new int[2];
#Override
public void onMeasure(RecyclerView.Recycler recycler, RecyclerView.State state,
int widthSpec, int heightSpec) {
final int widthMode = View.MeasureSpec.getMode(widthSpec);
final int heightMode = View.MeasureSpec.getMode(heightSpec);
final int widthSize = View.MeasureSpec.getSize(widthSpec);
final int heightSize = View.MeasureSpec.getSize(heightSpec);
int width = 0;
int height = 0;
for (int i = 0; i < getItemCount(); i++) {
measureScrapChild(recycler, i,
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
View.MeasureSpec.makeMeasureSpec(i, View.MeasureSpec.UNSPECIFIED),
mMeasuredDimension);
if (getOrientation() == HORIZONTAL) {
width = width + mMeasuredDimension[0];
if (i == 0) {
height = mMeasuredDimension[1];
}
} else {
height = height + mMeasuredDimension[1];
if (i == 0) {
width = mMeasuredDimension[0];
}
}
}
switch (widthMode) {
case View.MeasureSpec.EXACTLY:
width = widthSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
switch (heightMode) {
case View.MeasureSpec.EXACTLY:
height = heightSize;
case View.MeasureSpec.AT_MOST:
case View.MeasureSpec.UNSPECIFIED:
}
setMeasuredDimension(width, height);
}
private void measureScrapChild(RecyclerView.Recycler recycler, int position, int widthSpec,
int heightSpec, int[] measuredDimension) {
View view = recycler.getViewForPosition(position);
if (view != null) {
RecyclerView.LayoutParams p = (RecyclerView.LayoutParams) view.getLayoutParams();
int childWidthSpec = ViewGroup.getChildMeasureSpec(widthSpec,
getPaddingLeft() + getPaddingRight(), p.width);
int childHeightSpec = ViewGroup.getChildMeasureSpec(heightSpec,
getPaddingTop() + getPaddingBottom(), p.height);
view.measure(childWidthSpec, childHeightSpec);
measuredDimension[0] = view.getMeasuredWidth() + p.leftMargin + p.rightMargin;
measuredDimension[1] = view.getMeasuredHeight() + p.bottomMargin + p.topMargin;
recycler.recycleView(view);
}
}
}
You can use ItemTouchHelper in supportv7, and implement simplecallback,like this:
mSimpleCallback = new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.LEFT|ItemTouchHelper.RIGHT|ItemTouchHelper.UP|ItemTouchHelper.DOWN, 0) {
#Override
public boolean onMove(RecyclerView recyclerView, RecyclerView.ViewHolder viewHolder, RecyclerView.ViewHolder target) {
int fromPosition = viewHolder.getAdapterPosition();//得到拖动ViewHolder的position
int toPosition = target.getAdapterPosition();//得到目标ViewHolder的position
List<NHUser.DescriptionEntity> datas = mItemAdapter.getData();
if (fromPosition < toPosition) {
//分别把中间所有的item的位置重新交换
for (int i = fromPosition; i < toPosition; i++) {
Collections.swap(datas, i, i + 1);
}
} else {
for (int i = fromPosition; i > toPosition; i--) {
Collections.swap(datas, i, i - 1);
}
}
mItemAdapter.notifyItemMoved(fromPosition, toPosition);
return true;
}
#Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
}
};
historically i have stupid problems with layouts, and now i try to fill this blank in my brain. Watch this example, i try to do some axis for graphic, and i want to pack them like this:
Vertical line by left side
Horizontal line by bottom
Spacer between Vert & Horiz in left bottom corner
Other place fill by graph
(Sorry not allowed to post images.I hope you see graphics axis before, no need to explain.)
And this what i got at now:
<?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" >
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<com.example.graphicformatting.Axis
android:id="#+id/yaxis"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_marginBottom="40dp"
android:background="#color/backpanel_dark"
custom:ishorizontal="false" />
<EditText
android:id="#+id/editText1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:ems="10"
android:inputType="textMultiLine"
android:text="This text field mean my own graphic widget, which not have any OnMeasured function or any specific and it's painting with size, which assigment by parent/ Just use getHeight and getWeight" >
<requestFocus />
</EditText>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content" >
<View
android:layout_width="40dp"
android:layout_height="40dp"
android:background="#color/backpanel_dark" />
<com.example.graphicformatting.Axis
android:id="#+id/yaxis"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="40dp"
android:background="#color/backpanel_dark"
custom:ishorizontal="true" />
</LinearLayout>
And this is code of my axises:
package com.example.graphicformatting;
public class Axis extends View {
public static final int HORIZONTAL = 0;
public static final int VERTICAL = 1;
public static final int DP_SIZE = 40;
int type = -1;
int size;
Paint painter;
public Axis(Context context, AttributeSet attrs) {
super(context, attrs);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.com_example_graphicformatting_Axis);
final int N = a.getIndexCount();
for (int i = 0; i < N; ++i) {
int attr = a.getIndex(i);
switch (attr) {
case R.styleable.com_example_graphicformatting_Axis_ishorizontal:
if (a.getBoolean(attr, true)) {
type = HORIZONTAL;
} else
type = VERTICAL;
break;
default:
Log.d("axis", "Found unexpected state");
}
}
a.recycle();
final float scale = getContext().getResources().getDisplayMetrics().density;
size = (int) (DP_SIZE * scale + 0.5f);
painter = new Paint();
painter.setColor(Color.RED);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int parentWidth = MeasureSpec.getSize(widthMeasureSpec);
int parentHeight = MeasureSpec.getSize(heightMeasureSpec);
if (type == HORIZONTAL) {
this.setMeasuredDimension(parentWidth, size);
this.setLayoutParams(new LinearLayout.LayoutParams(parentWidth, size));
// Log.d("axis", "Size of horizontal calc: " + (parentWidth) + " "
// + size);
} else if (type == VERTICAL) {
this.setMeasuredDimension(size, parentHeight);
this.setLayoutParams(new LinearLayout.LayoutParams(size, parentHeight));
// Log.d("axis", "Size of vertical calc: " + size + " "
// + (parentHeight));
} else { // Для нормального отображения в конструкторе
this.setMeasuredDimension(size, size);
this.setLayoutParams(new LinearLayout.LayoutParams(size, size));
}
}
#Override
protected void onDraw(Canvas canvas) {
if (type == VERTICAL) {
canvas.drawRect(0, 0, size, getHeight(), painter);
} else {
canvas.drawRect(0, getHeight() - size, getWidth(), getHeight(), painter);
}
super.onDraw(canvas);
}
}
How to custom my Layouts to get right pic?
Ou, this using for set horizontal/vertical attribute (value/attrs.xml)
<?xml version="1.0" encoding="utf-8"?>
<resources>
<declare-styleable name="com.example.graphicformatting.Axis">
<attr name="ishorizontal" format="boolean"></attr>
</declare-styleable>
</resources>
In one of my activities, I'd like to have something like a 'menubar', positioned at the bottom of the screen in portrait mode and at the right of the screen in landscape mode.
The menubar is permanently visible and will house imagebuttons, which have the same height but may have different widths. According to the number of 'buttons' in the 'menubar' a proper padding is chosen, so that the available height or witdh is used properly.
Basically it should look like this:
I already considered using a 'split action bar', as suggested here. But in this case I only have the desired effect in portrait mode.
At the moment I consider to implement a custom gridview layout to get this effect, or to modify the dashboard pattern found here.
Maybe some of you already implemented something like a 'menubar like layout' and can point me in the right direction.
EDIT
I slightly modified the dashboard pattern code mentioned above, it's just a first proof of concept, but seems to do what I intended:
public class Nx1Layout extends ViewGroup {
private static final String TAG = "Nx1Layout";
private int mMaxChildWidth = 0;
private int mMaxChildHeight = 0;
private int mScreenOrientation = Configuration.ORIENTATION_PORTRAIT;
public Nx1Layout(Context context) {
super(context, null);
}
public Nx1Layout(Context context, AttributeSet attrs) {
super(context, attrs, 0);
}
public Nx1Layout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public void setScreenOrientation(int screenOrientation) {
mScreenOrientation = screenOrientation;
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mMaxChildWidth = 0;
mMaxChildHeight = 0;
// Measure once to find the maximum child size.
int childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(widthMeasureSpec), MeasureSpec.AT_MOST);
int childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(MeasureSpec.getSize(heightMeasureSpec), MeasureSpec.AT_MOST);
final int count = getChildCount();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
mMaxChildWidth = Math.max(mMaxChildWidth, child.getMeasuredWidth());
mMaxChildHeight = Math.max(mMaxChildHeight, child.getMeasuredHeight());
}
// Measure again for each child to be exactly the same size.
childWidthMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildWidth, MeasureSpec.EXACTLY);
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(mMaxChildHeight, MeasureSpec.EXACTLY);
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
child.measure(childWidthMeasureSpec, childHeightMeasureSpec);
}
setMeasuredDimension(resolveSize(mMaxChildWidth, widthMeasureSpec),resolveSize(mMaxChildHeight, heightMeasureSpec));
}
#Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
int width = r - l;
int height = b - t;
final int count = getChildCount();
// Calculate the number of visible children.
int visibleCount = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
++visibleCount;
}
if (visibleCount == 0) {
return;
}
// Horizontal and vertical space between items
int hSpace = 0;
int vSpace = 0;
int cols, rows;
if(mScreenOrientation == Configuration.ORIENTATION_PORTRAIT) {
cols = visibleCount;
rows = 1;
} else {
cols = 1;
rows = visibleCount;
}
hSpace = ((width - mMaxChildWidth * cols) / (cols + 1));
vSpace = ((height - mMaxChildHeight * rows) / (rows + 1));
// Lay out children based on calculated best-fit number of rows and cols.
// If we chose a layout that has negative horizontal or vertical space, force it to zero.
hSpace = Math.max(0, hSpace);
vSpace = Math.max(0, vSpace);
// Re-use width/height variables to be child width/height.
width = (width - hSpace * (cols + 1)) / cols;
height = (height - vSpace * (rows + 1)) / rows;
int left, top;
int col, row;
int visibleIndex = 0;
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() == GONE) {
continue;
}
row = visibleIndex / cols;
col = visibleIndex % cols;
left = hSpace * (col + 1) + width * col;
top = vSpace * (row + 1) + height * row;
child.layout(left, top, (hSpace == 0 && col == cols - 1) ? r : (left + width), (vSpace == 0 && row == rows - 1) ? b : (top + height));
++visibleIndex;
}
}
}
Here's some activity code to test it:
public class TestActivity extends SherlockFragmentActivity {
#Override
public void onCreate(Bundle savedInstanceState) {
// setup ui
super.onCreate(savedInstanceState);
setContentView(R.layout.ui_test);
Nx1Layout layout = (Nx1Layout)findViewById(R.id.layout1);
layout.setScreenOrientation(getScreenOrientation());
}
public int getScreenOrientation()
{
Display getOrient = getWindowManager().getDefaultDisplay();
int orientation = Configuration.ORIENTATION_UNDEFINED;
if(getOrient.getWidth() == getOrient.getHeight()){
orientation = Configuration.ORIENTATION_SQUARE;
} else{
if(getOrient.getWidth() < getOrient.getHeight()){
orientation = Configuration.ORIENTATION_PORTRAIT;
}else {
orientation = Configuration.ORIENTATION_LANDSCAPE;
}
}
return orientation;
}}
here's the layout file for portrait mode:
<?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" >
<com.yourpackagename.Nx1Layout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="70dp"
android:id="#+id/layout1">
<ImageView
android:id="#+id/image1"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw" />
<ImageView
android:id="#+id/image2"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw" />
<ImageView
android:id="#+id/image3"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw" />
</com.yourpackagename.Nx1Layout>
</LinearLayout>
and here the layout file for landscape mode:
<?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" >
<com.yourpackagename.Nx1Layout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="70dp"
android:layout_height="match_parent"
android:id="#+id/layout1">
<ImageView
android:id="#+id/image1"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw" />
<ImageView
android:id="#+id/image2"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw_narrow" />
<ImageView
android:id="#+id/image3"
android:layout_width="70dp"
android:layout_height="70dp"
android:contentDescription="some description"
android:scaleType="centerInside"
android:padding="2dp"
android:src="#drawable/test_draw" />
</com.yourpackagename.Nx1Layout>
</LinearLayout>
last but not least some drawable I used:
Feel free to comment on this solution...