Leanback VerticalGridFragment remove top spacing - android

I am using VerticalGridFragment to display items in a grid-like layout
I don't need to show search or title and I want the rows to start from top of the screen without any margins. Any help?

I found a way to do it by overriding the VerticalGridPresenter of the VerticalGridFragment then getting the VerticalGridView, and setting top padding to a smaller value.
In the CustomVerticalGridPresenter class (that extends VerticalGridPresenter), override this method:
#Override
protected void initializeGridViewHolder(ViewHolder vh) {
super.initializeGridViewHolder(vh);
gridView = vh.getGridView();
int top= 20;//this is the new value for top padding
int bottom = gridView.getPaddingBottom();
int right = gridView.getPaddingRight();
int left = gridView.getPaddingLeft();
gridView.setPadding(left,top,right,bottom);
}
Then in the VerticalGridFragment, assign the new CustomVerticalGridPresenter as following:
CustomVerticalGridPresenter gridPresenter = new CustomVerticalGridPresenter();
gridPresenter.setNumberOfColumns(NUM_COLUMNS);
setGridPresenter(gridPresenter);

You need create new class with name CustomVerticalGridPresenter and put followig code in it.
public class CustomVerticalGridPresenter extends VerticalGridPresenter {
VerticalGridView gridView;
CustomVerticalGridPresenter(int zoom, boolean val){
super(zoom, val);
}
#Override
protected void initializeGridViewHolder(ViewHolder vh) {
super.initializeGridViewHolder(vh);
gridView = vh.getGridView();
int top = 20;//this is the new value for top padding
int bottom = gridView.getPaddingBottom();
int right = gridView.getPaddingRight();
int left = gridView.getPaddingLeft();
gridView.setPadding(left,top,right,bottom);
}
}
Then in verticalgridfragment class use
CustomVerticalGridPresenter videoGridPresenter = new
CustomVerticalGridPresenter(ZOOM_FACTOR, false);
instead of
VerticalGridPresentervideoGridPresenter = new VerticalGridPresenter(ZOOM_FACTOR, false);

Another way over this problem is to set the windowAlignment attributes of the VerticalGridView. Most notably ...
verticalGridView.windowAlignment = BaseGridView.WINDOW_ALIGN_LOW_EDGE //this will remove the top margin
verticalGridView.windowAlignmentOffset = 0
verticalGridView.windowAlignmentOffsetPercent = 25f //find correct values for your case

First of follow this steps to move the rows up which is by default given margins by Lean back Library.
1. Go to you SDK.
2. Inside SDK -> extras -> android -> support -> v17 -> leanback -> res -> values.
3. Inside values folder copy the dimens.xml inside your current project and copy to your projects res -> values folder.
Now you have the file name dimens.xml inside your values folder.
Now open the dimens.xml file which you have copied.
Change the value for property defined below. By default it will given 168dp around that. So make it less to decrease the top margin as i have given below.
<dimen name="lb_browse_rows_margin_top">35dp</dimen>
Now you can be able to split your rows up exact below of top section of your Browse Fragment.

The best way is to create a theme and set it for your Activity / Fragment.
In themes.xml:
<style name="AppTheme.Leanback.NoTitle" parent="Theme.Leanback.Browse">
<item name="browseRowsMarginTop">#dimen/lb_browse_rows_margin_top_none</item>>
</style>
in dimens.xml
<dimen name="lb_browse_rows_margin_top_none">32dp</dimen>

Related

Anko ignoring layout_margin defined in style

I created a custom style:
<style name="Static">
<item name="android:layout_width">wrap_content</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_marginEnd">5dp</item>
</style>
Then I extended anko with a static function:
inline fun ViewManager.static(theme: Int = R.style.Static, init: TextView.() -> Unit) = ankoView(::TextView, theme, init)
When I use this in my layout:
static { text = resources.getString(R.string.name) }
The marginEnd value is ignored.
If I add a margin manually in anko:
static { text = resources.getString(R.string.name) }.lparams { marginEnd = dip(5) }
The margin is fine.
Do you guys know what is happening that anko is ignoring my margin value or any other way to define a predefined margin for a extended view anko function?
This is not Anko problem, this is how Android works:
If you are specifying layout_margin in a custom style, this style must be explicitly applied to each individual view that you wish to have the specified margin (as seen in the code sample below). Including this style in a theme and applying it to your application or an activity will not work.
This is because attributes which begin with layout_ are LayoutParams, or as in this example its MarginLayoutParams. Each ViewGroup have it's own LayoutParams implementation. And so layout_margin is not just general attribute that can be applied anywhere. It must be applied within the context of a ViewGroup that specifically defines it as a valid argument.
Look here for more.
As #John pointed in his answer, using a style is not an option to define layout params.
So, I developed a function to use in the applyRecursively that iterates over the views and apply the layouts that I want to apply.
The solution:
I wanted to define matchParent for width and height and a margin of 16dp for a TableView, so I created a new class that extends TableLayout
class TableViewFrame(context: Context) : TableLayout(context)
and then in the function when the view is a TableViewFrame I apply my layouts
fun applyTemplateViewLayouts(view: View) {
when(view) {
is TableViewFrame -> {
when(view.layoutParams) {
is LinearLayout.LayoutParams -> {
view.layoutParams.height = matchParent
view.layoutParams.width = matchParent
(view.layoutParams as LinearLayout.LayoutParams).margin = view.dip(16)
}
}
}
}
}
To use the function, in the view definition, I just pass it in the applyRecursively:
verticalLayout {
tableViewFrame {
tableRow {
...
}
}
}
}.applyRecursively { view -> applyTemplateViewLayouts(view) }
I wrote an article at medium with a more detailed explanation: https://medium.com/#jonathanrafaelzanella/using-android-styles-with-anko-e3d5341dd5b4

Android TextView baseline related margin

I need to position a TextView the way its baseline is 20dp from the bottom of the container.
How can I achieve this?
The layout with bottom margin or padding produces the same result.
I would like to make the text 'sit' on the purple line.
When I write 'sit' I mean, the 'wert' should touch the line, not 'q...y'.
The padding / margin is equal to the purple square size:
If you still need it, I wrote custom method, to not create lots of custom views. It works for me with TextView:
public static void applyExistingBotMarginFromBaseline(View view) {
final int baseline = view.getBaseline();
final int height = view.getHeight();
final ViewGroup.MarginLayoutParams marginLayoutParams;
try {
marginLayoutParams = ((ViewGroup.MarginLayoutParams) view.getLayoutParams());
} catch (ClassCastException e) {
throw new IllegalArgumentException("Applying margins on a view with wrong layout params.");
}
final int baselineMarginValue = baseline + marginLayoutParams.bottomMargin;
marginLayoutParams.bottomMargin = baselineMarginValue - height;
view.setLayoutParams(marginLayoutParams);
}
You can apply it when view is measured already, so like this:
final TextView title = (TextView) findViewById(R.id.title);
title.post(new Runnable() {
#Override public void run() {
Utils.applyExistingBotMarginFromBaseline(title);
}
});
Also you can use databinding framework and write your own custom BindingAdapter with a bit customized method, to use it from xml.
Your problem is not the padding/margin referenced to the parent, I think is about your font, I recommend you to change the fontFamily:"yourStyle"
even worst you have to re-difine your own font style which is explained here Custom fonts and XML layouts (Android) or Set specific font in a styles.xml

Animate view's width to match parent?

I want to create the following concept:
First expand the view to its parent's width (it's not the same).
Then expand the view to its parent's height.
I know I can create the sequence with AnimatorSet(). What I cannot find is what property/-ies to animate to create the result.
My thoughts for the width animation:
I would probably need to animate either two points which define left and right or alternatively animate the translation and the width.
I'm a bit confused, which properties would do the trick?
You'll need to define custom properties to do this (I know, silly). Height example:
public static final Property<View, Integer> PROPERTY_HEIGHT =
new Property<View, Integer>(Integer.class, "viewLayoutHeight") {
#Override
public void set(View object, Integer value) {
object.getLayoutParams().height = value.intValue();
object.requestLayout();
}
#Override
public Integer get(View object) {
return object.getLayoutParams().height;
}
};
Then use as a normal property:
ObjectAnimator.ofInt(view, PROPERTY_HEIGHT, minHeight, maxHeight);
You'll need to get the parent dimensions at runtime (perhaps using a ViewTreeObserver.OnGlobalLayoutListener).
I think that there is no need to complicate things, you can use width property first then followed by height in AnimatorSet, Your view gravity property will define in which direction view will expand ...

How do I set the maximum length for a spinner's drop-down list?

I have a spinner which currently obscures some text below the spinner when opened. I need to limit the maximum drop-down length of the spinner, either through java code or through XML, so that it does not obscure this text.
The current design is the left example while the desired design is on the right.
How do I go about limiting how far the spinner drops down to when opened? At present, it drops down to fill the entire portion of screen below it.
One way to achieve this is to use ActionBarSherlock's IcsSpinner. I made the needed modifications to limit the size of the spinner and that seems to work nicely.
Make the following modifications to IcsListPopupWindow.
Add an instance variable:
private int mDropDownVerticalOffsetBottom;
Add a method to set this variable:
public void setVerticalOffsetBottom(int offsetBottom) {
mDropDownVerticalOffsetBottom = offsetBottom;
}
Alter the call to getMaxAvailableHeight to (mDropDownVerticalOffsetBottom was added):
final int maxHeight = /*mPopup.*/getMaxAvailableHeight(
mDropDownAnchorView, mDropDownVerticalOffset, mDropDownVerticalOffsetBottom, ignoreBottomDecorations);
Change the method's signature to include that variable:
private int getMaxAvailableHeight(View anchor, int yOffset, int yOffsetBottom, boolean ignoreBottomDecorations) {
And consider that offset when computing the distance to the bottom:
final int distanceToBottom = bottomEdge - (anchorPos[1] + anchor.getHeight()) - yOffset - yOffsetBottom;
Now modify IcsSpinner.java to implement the setter method for the offset:
private DropdownPopup mPopup; // <- needs to be a DropdownPopup instead of a SpinnerPopup
public void setVerticalOffsetBottom(int offsetBottom) {
mPopup.setVerticalOffsetBottom(offsetBottom);
}
Now "all" you need to do is to set the offset to the correct value. Here's how I did it (I tested it and it worked on two test devices):
final View root = findViewById(R.id.root_layout);
final View view = findViewById(R.id.view_not_to_be_obscured);
root.getViewTreeObserver().addOnGlobalLayoutListener(new OnGlobalLayoutListener() {
public void onGlobalLayout() {
root.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int[] locations = new int[2];
root.getLocationOnScreen(locations);
int y1 = locations[1];
int h1 = root.getHeight();
view.getLocationOnScreen(locations);
int y2 = locations[1];
int offset = y1 + h1 - y2;
// here we initialize the spinner
}
});
The assumption is that root_layout fills the whole window excluding all decorating elements.
The final step is to create the spinner itself:
// actionDropDownStyle is an attribute set in the theme to e.g. #style/Widget.Sherlock.Spinner.DropDown.ActionBar or #style/Widget.Sherlock.Light.Spinner.DropDown.ActionBar for light theme
IcsSpinner spinner = new IcsSpinner(context, null, R.attr.actionDropDownStyle);
// yes here we set the offset!
spinner.setVerticalOffsetBottom(offset);
spinner.setPadding(spinner.getPaddingLeft(), 0, spinner.getPaddingRight(), 0);
spinner.setId(R.id.some_id);
spinner.setAdapter(yourAdapter); // you can use a simple ArrayAdapter or whatever you need
// create ICS LinearLayout
LayoutInflater inflater = (LayoutInflater) context.getSystemService( Context.LAYOUT_INFLATER_SERVICE );
IcsLinearLayout linearLayout = (IcsLinearLayout) inflater.inflate(R.layout.abs__action_bar_tab_bar_view, null);
linearLayout .setPadding(listNavLayout.getPaddingLeft(), 0, listNavLayout.getPaddingRight(), 0);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.MATCH_PARENT);
params.gravity = Gravity.CENTER;
linearLayout .addView(spinner, params);
Now that might look complicated but as someone else mentioned, you'll not be able to achieve this without your own spinner implementation and since ActionBarSherlock comes with one, why not use it? It's certainly less work than writing your own one. If you don't use the library for the ActionBar strip away all resource files you don't need and use Proguard to strip away all unused classes.
You could probably achieve the same using AppCompat (see here: https://github.com/android/platform_frameworks_support/tree/master/v7/appcompat/src/android/support).
I've searched quite a bit and it seems that I can't find a solution to this anywhere. You may have to go a slightly different route by recreating the functionality of a spinner, but using buttons and dialogs intead.
Assuming you're using an ArrayAdapter for the spinner, try this:
Replace your Spinner with a button that has a down arrow icon.
Create a custom Dialog or AlertDialog and populate a ListView with the ArrayAdapter.
For the onClick method, push the value of the selected option and populate a static variable and the text of the button with the chosen value. This way, you can make the size of the dialog box any size you want and the excess choices will always be scrollable.
I know it's not ideal, but I haven't found any way to change the height of the "dropdown" portion of a spinner.
Sorry if this wasn't what you were hoping for.
EDIT: Someone else asked the exact same question here before and it turns out they went with the exact method I just described. You can see the sample code they used here: Check out the question/code
in Kotlin, This what i've done to set dropdwon spinner height.
Replace "spinner_empresas" with your spinner id.
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
view.setOnClickListener(this)
binding?.spinnerEmpresas?.adapter = ArrayAdapter(this,
android.R.layout.simple_spinner_item, arrayOf("items"))
val popup: Field =
AppCompatSpinner::class.java.getDeclaredField("mPopup")
popup.isAccessible = true
val popupWindow = popup[spinner_empresas] as
androidx.appcompat.widget.ListPopupWindow
popupWindow.height = 700
}
}
you can use relfection.
Spinner spinner = (Spinner) findViewById(R.id.spinner);
try {
Field popup = Spinner.class.getDeclaredField("mPopup");
popup.setAccessible(true);
// Get private mPopup member variable and try cast to ListPopupWindow
android.widget.ListPopupWindow popupWindow = (android.widget.ListPopupWindow) popup.get(spinner);
// Set popupWindow height to 500px
popupWindow.setHeight(500);
}
catch (NoClassDefFoundError | ClassCastException | NoSuchFieldException | IllegalAccessException e) {
// silently fail...
}
But if you are using androidx.appCompat 1.1.0 then you have to use ->
I can't use API reflection on androidx.appcompat:appcompat:1.1.0
Regards
I think you have to use custom spinner for your requirement .There is not any inbuilt method or xml property that can help.
See this example for help .
https://github.com/ankitthakkar/DropDownSpinner
Hope this will work.
Note: This is changed answer.

Actionbarsherlock getHeight() returns 0

I'm using Actionbarsherlock and I want to place a PopupWindow right below the action bar. Using the showAtLocation() takes an x and y offset, so ideally the y offset would be the height of the action bar. But when I call
int abHeight = getSupportActionBar().getHeight();
it returns zero. I'm using a SherlockFragmentActivity
Here's the relevant code:
slidingLayout = inflater.inflate(R.layout.sliding_menu, null);
menuDrawer = MenuDrawer.attach(this, MenuDrawer.MENU_DRAG_CONTENT, Position.LEFT);
menuDrawer.setContentView(R.layout.activity_main);
menuDrawer.setMenuView(slidingLayout.findViewById(R.id.sliding_menu));
getSupportActionBar().setNavigationMode(ActionBar.NAVIGATION_MODE_STANDARD);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
int abHeight = getSupportActionBar().getHeight();
I've looked all over and can't find a similar question/answer, so has anyone experienced this before? Thanks.
EDIT: Jake's answer was right on. In order to get that attribute value I used this post.
You can read the height of the action bar from the actionBarSize theme attribute. This changes based on the device configuration so make sure you are always reading it when your activity is created or recreated.
in you style.XML add: <item name="#android:attr/actionBarSize">50px</item>
and then in your activity add the following code :
TypedArray actionbarSizeTypedArray = mContext.obtainStyledAttributes(new int[] { android.R.attr.actionBarSize});
int h = (int) actionbarSizeTypedArray.getDimension(0, 0);
this is one kind ,I am trying to get other ways.Good luck!
Yeah!I find a way very simple:
TypedValue tv = new TypedValue();
if (getTheme().resolveAttribute(android.R.attr.actionBarSize, tv, true))
{
int h=TypedValue.complexToDimensionPixelSize(tv.data,getResources().getDisplayMetrics());
}
more info,look this link
You can't get the height for views until they have been layed out. Try adding a ViewTreeObserver:
someView.getViewTreeObserver().addGlobalLayoutListener(new OnGlobalLayoutListener() {
#Override
public void onGlobalLayout() {
// Remember to remove it if you don't want it to fire every time
someView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
int abHeight = getSupportActionBar().getHeight();
// Use the height as desired...
}
});
Refer to the docs starting at View.getViewTreeObserver().

Categories

Resources