the goal is to create 5x5 grid buttons and fill the screen
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
LinearLayout layout = new LinearLayout(this);
layout.setOrientation(LinearLayout.VERTICAL); //Can also be done in xml by android:orientation="vertical"
int widthOfCell = (int) squareSize(screenWidth().widthPixels, screenWidth().heightPixels, 9);
for (int i = 0; i < 5; i++) {
LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new ViewGroup.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
for (int j = 0; j < 5; j++) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(0, 0, 1.0f);
DynamicSquareLayout btnTag = new DynamicSquareLayout(this);
btnTag.setLayoutParams(param);
btnTag.setText("Button " + (j + 1 + (i * 4 )));
btnTag.setId(j + 1 + (i * 4));
row.addView(btnTag);
}
layout.addView(row);
}
setContentView(layout);
}
class DynamicSquareLayout extends Button {
public DynamicSquareLayout(Context context) {
super(context);
}
public DynamicSquareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public DynamicSquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(size, size);
}
}
However it doesn't fill all screen , how to modify it to fill the screen although the buttons are squares
You need to set
row.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f)); as your row layout params so that all 5 rows get evenly distributed in the layout. Here's the full code:
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
context = this;
LinearLayout layout = new LinearLayout(this);
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
layout.setOrientation(LinearLayout.VERTICAL); //Can also be done in xml by android:orientation="vertical"
int widthOfCell = 20; //(int) squareSize(screenWidth().widthPixels, screenWidth().heightPixels, 9);
for (int i = 0; i < 5; i++) {
LinearLayout row = new LinearLayout(this);
row.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1.0f));
for (int j = 0; j < 5; j++) {
LinearLayout.LayoutParams param = new LinearLayout.LayoutParams(0, 0, 1.0f);
DynamicSquareLayout btnTag = new DynamicSquareLayout(this);
btnTag.setLayoutParams(param);
btnTag.setText("Button " + (j + 1 + (i * 4 )));
btnTag.setId(j + 1 + (i * 4));
row.addView(btnTag);
}
layout.addView(row);
}
layout.setLayoutParams(params);
setContentView(layout);
}
class DynamicSquareLayout extends android.support.v7.widget.AppCompatButton {
public DynamicSquareLayout(Context context) {
super(context);
}
public DynamicSquareLayout(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public DynamicSquareLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
#Override public void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, widthMeasureSpec);
int size = MeasureSpec.getSize(widthMeasureSpec);
setMeasuredDimension(size, size);
}
}
Related
In View pager Tab Layout, when ever I have single tab, tab heading is not coming to center and tab indicator is not occupying whole layout, but when there is more than 1 tabs its dividing and occupying whole. I have used custom tab layout class.
My custom tab layout code is :-
public class OPTCustomTab extends TabLayout {
public OPTCustomTab(Context context) {
super(context);
}
public OPTCustomTab(Context context, AttributeSet attrs) {
super(context, attrs);
}
public OPTCustomTab(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
#Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
ViewGroup tabLayout = (ViewGroup) getChildAt(0);
int childCount = tabLayout.getChildCount();
if (childCount != 0) {
DisplayMetrics displayMetrics = getContext().getResources().getDisplayMetrics();
int tabMinWidth = displayMetrics.widthPixels / childCount;
for (int i = 0; i < childCount; ++i) {
tabLayout.getChildAt(i).setMinimumWidth(tabMinWidth);
}
}
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
}
}
I have tried giving this,
app:tabMaxWidth="0dp"
app:tabGravity="fill"
I have tried to overwrite onOverScrolled() but it is not triggered:
public class MyRecyclerView extends RecyclerView {
public MyRecyclerView(#NonNull Context context) {
super(context);
}
public MyRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
}
public MyRecyclerView(#NonNull Context context, #Nullable AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
#Override
protected void onOverScrolled(int scrollX, int scrollY, boolean clampedX, boolean clampedY) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY);
Toast.makeText(getContext(), "overScrolled", Toast.LENGTH_SHORT).show();
}
}
My RecyclerView has recyclerView.setOverScrollMode(View.OVER_SCROLL_ALWAYS);
Try this to find bottom overscroll and top overscroll
Find bottom overscroll and top overscroll Using LayoutManager
import android.os.Bundle;
import java.util.ArrayList;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
public class MainActivity extends AppCompatActivity {
RecyclerView myRecyclerView;
ArrayList<String> arrayList = new ArrayList<>();
DataAdapter adapter;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
myRecyclerView = findViewById(R.id.myRecyclerView);
LinearLayoutManager linearLayoutManager= new LinearLayoutManager(this){
#Override
public int scrollVerticallyBy ( int dx, RecyclerView.Recycler recycler, RecyclerView.State state ) {
int scrollRange = super.scrollVerticallyBy(dx, recycler, state);
int overScroll = dx - scrollRange;
if (overScroll > 0) {
Utils.printLog("NILU_PILU :-> BOTTOM OVERSCROLL");
} else if (overScroll < 0) {
Utils.printLog("NILU_PILU :-> TOP OVERSCROLL");
}
return scrollRange;
}
};
myRecyclerView.setLayoutManager(linearLayoutManager);
myRecyclerView.setHasFixedSize(true);
addDataToList();
adapter = new DataAdapter(this, arrayList);
myRecyclerView.setAdapter(adapter);
}
private void addDataToList() {
for (int i = 0; i < 50; i++) {
arrayList.add("NILU_PILU :-> " + i);
}
}
}
Find bottom overscroll Using RecyclerView.addOnScrollListener()
myRecyclerView.addOnScrollListener(new RecyclerView.OnScrollListener() {
#Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
super.onScrolled(recyclerView, dx, dy);
if (dy > 0) {
int pos = linearLayoutManager.findLastVisibleItemPosition();
int numItems = myRecyclerView.getAdapter().getItemCount();
if (pos >= numItems - 1 ) {
Utils.printLog("NILU_PILU :-> BOTTOM OVERSCROLL");
}
}
}
});
Here is a solution I found on reddit:
Instead of a custom recyclerview, you create a custom LinearLayoutManager and just overwrite your layout managers scrollVerticallyBy() method and check if dx/dy minus the value returned by the super implementation is != 0. Then overscroll has occured.
#Override
public int scrollVerticallyBy ( int dx, RecyclerView.Recycler recycler,
RecyclerView.State state ) {
int scrollRange = super.scrollVerticallyBy(dx, recycler, state);
int overscroll = dx - scrollRange;
if (overscroll > 0) {
// bottom overscroll
} else if (overscroll < 0) {
// top overscroll
}
return scrollRange;
}
I have put one recycler view in my project. I want that it will be auto-scroll horizontally. For achieving this I have made one custom class. but I also want that existing functions which I put on my recycler view will also remain.
CustomLinearLayoutManager:
public class CustomLinearLayoutManager extends LinearLayoutManager {
public CustomLinearLayoutManager (Context context) {
super(context);
}
public CustomLinearLayoutManager(Context context, int orientation, boolean reverseLayout) {
super(context, orientation, reverseLayout);
}
public CustomLinearLayoutManager(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
#Override
public void smoothScrollToPosition(RecyclerView recyclerView, RecyclerView.State state, int position) {
final LinearSmoothScroller linearSmoothScroller =
new LinearSmoothScroller(recyclerView.getContext()) {
private static final float MILLISECONDS_PER_INCH = 200f;
#Override
public PointF computeScrollVectorForPosition(int targetPosition) {
return CustomLinearLayoutManager.this
.computeScrollVectorForPosition(targetPosition);
}
#Override
protected float calculateSpeedPerPixel
(DisplayMetrics displayMetrics) {
return MILLISECONDS_PER_INCH / displayMetrics.densityDpi;
}
};
linearSmoothScroller.setTargetPosition(position);
startSmoothScroll(linearSmoothScroller);
}
}
Home Class
private RecyclerView recyclerViewHeaderSlider;
private HeaderSliderAdapter headerSliderAdapter;
private List<Banner> banners;
banners = new ArrayList<>();
headerSliderAdapter = new HeaderSliderAdapter(getActivity(), banners);
recyclerViewHeaderSlider = view.findViewById(R.id.bannerSlider);
SnapHelper snapHelper = new PagerSnapHelper();
snapHelper.attachToRecyclerView(recyclerViewHeaderSlider);
recyclerViewHeaderSlider.setHasFixedSize(true);
recyclerViewHeaderSlider.setLayoutManager(new LinearLayoutManager(getActivity(), LinearLayoutManager.HORIZONTAL, false));
headerSliderAdapter.setOnClick(this);
recyclerViewHeaderSlider.setAdapter(headerSliderAdapter);
I want to implement my custom linear layout manager with Home class.
You can use Runnable to autoscroll Horizontal RV
public void autoScroll(){
speedScroll = 0;
handler = new Handler();
runnable = new Runnable() {
int count = 0;
#Override
public void run() {
if(count == tickerAdapter.getItemCount())
count = 0;
else {
if(count < tickerAdapter.getItemCount()){
rvTicker.smoothScrollToPosition(++count);
handler.postDelayed(this,speedScroll);
}else {
count = 0;
}
}
}
};
handler.postDelayed(runnable,speedScroll);
}
I already know how to use a custom component in a xml. Now, I'm trying to call one programmatically. I haven't found any tutorial about this so I tried to do it like how we declare a view programmatically. One problem I stumbled upon is that how do I get an AttributeSet that I pass on my constructor? I don't know how I get or create that to pass it for my custom component.
This is my custom component class.
public class CheckOutItem extends ConstraintLayout {
public Context ctx;
public Paint mPaint;
public Rect mRect;
int mSquareColor;
public ImageView imgThumbnail;
public TextView lblAbbrev, lblFullName;
public ConstraintLayout lytMain;
String TAG = "sharePOS";
public CheckOutItem(Context context) {
super(context);
ctx = context;
init(null);
}
public CheckOutItem(Context context, #Nullable AttributeSet attrs) {
super(context, attrs);
LayoutInflater.from(context).inflate(R.layout.checkout_item, this);
ctx = context;
init(attrs);
}
public CheckOutItem(Context context, #Nullable AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
ctx = context;
init(attrs);
}
private void init(#Nullable AttributeSet set){
//inflate(ctx, R.layout.checkout_item, this);
mPaint = new Paint(Paint.ANTI_ALIAS_FLAG);
mRect = new Rect();
if(set == null){
return;
}
TypedArray ta = getContext().obtainStyledAttributes(set, R.styleable.CheckOutItem);
this.imgThumbnail = findViewById(R.id.imgItemThumbnail);
this.lblAbbrev = findViewById(R.id.lblItemAbbrevName);
this.lblFullName = findViewById(R.id.lblItemFullName);
this.lytMain = findViewById(R.id.lytMain);
this.lblAbbrev.setText(ta.getText(R.styleable.CheckOutItem_abbrevText));
this.lblAbbrev.setTextSize(ta.getDimension(R.styleable.CheckOutItem_abbrevTextSize, 1f));
this.lblAbbrev.setTextColor(ta.getColor(R.styleable.CheckOutItem_abbrevTextColor, Color.BLACK));
this.lblFullName.setText(ta.getText(R.styleable.CheckOutItem_fullNameText));
this.lblFullName.setTextSize(ta.getDimension(R.styleable.CheckOutItem_fullNameTextSize, 1f));
this.lblFullName.setTextColor(ta.getColor(R.styleable.CheckOutItem_fullNameTextColor, Color.BLACK));
this.lblFullName.setBackgroundColor(ta.getColor(R.styleable.CheckOutItem_fullNameBackgroundColor, Color.WHITE));
this.lytMain.setBackgroundColor(ta.getColor(R.styleable.CheckOutItem_mainBackgroundColor, Color.LTGRAY));
this.lytMain.setBackground(ta.getDrawable(R.styleable.CheckOutItem_mainBackgroundDrawable));
ta.recycle();
}
#Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
mRect.left = 0;
mRect.right = getWidth();
mRect.top = 0;
mRect.bottom = getHeight();
Log.d(TAG, "rect: " + mRect);
canvas.drawRect(mRect, mPaint);
}
}
UPDATE:
How do I set a margin in the custom component? Regular LayoutParams with setMargins() doesn't seem to work.
I am passing a value to another class, I get the value in another class, but when I am using the value, it shows me 0.
public class MaterialSpinner extends Spinner implements ValueAnimator.AnimatorUpdateListener {
public int widths;
public MaterialSpinner(Context context, int width) {
super(context);
this.widths = width;
// **HERE SHOW ME VALUE FOR EXAMPLE 596**
Log.i("LOG-1", String.valueOf(widths));
init(context, null);
}
#Override
protected void onDraw(Canvas canvas) {
//BUT HERE GET ME 0**
int startX = this.widths;
Log.i("LOG-2", String.valueOf(widths));
}
}
I have other constructors:
public MaterialSpinner(Context context, AttributeSet attrs) {
super(context, attrs);
init(context, attrs);
}
public MaterialSpinner(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
init(context, attrs);
}
Here is my Activity; I pass the value from here to the MaterialSpinner class:
public class StartActivity extends AppCompatActivity {
Context context;
private ArrayAdapter<String> adapter;
int width;
int height;
MaterialSpinner spinner1;
private boolean shown = false;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
context = this;
if (android.os.Build.VERSION.SDK_INT < Build.VERSION_CODES.HONEYCOMB_MR2) {
Display display = getWindowManager().getDefaultDisplay();
width = display.getWidth();
height = display.getHeight();
}
else {
Display display = getWindowManager().getDefaultDisplay();
Point size = new Point();
display.getSize(size);
width = size.x;
height = size.y;
}
new MaterialSpinner(context, width);
adapter = new ArrayAdapter<String>(this, android.R.layout.simple_spinner_item, ITEMS);
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
initSpinnerHintAndFloatingLabel();
}
private void initSpinnerHintAndFloatingLabel() {
spinner1 = (MaterialSpinner) findViewById(R.id.spinner1);
spinner1.setAdapter(adapter);
spinner1.setPaddingSafe(0, 0, 0, 0);
}
}
you are creating an object, you do nothing with it:
new MaterialSpinner(context,width);
in the other function you do this:
spinner1 = (MaterialSpinner) findViewById(R.id.spinner1);
this will inflate the object from the activity_start layout. The easies way would be to create a setWidth() function and call it after you inflated the View
spinner1 = (MaterialSpinner) findViewById(R.id.spinner1);
spinner1.setWidth(width);
EDIT: and remove new MaterialSpinner(context,width); since it does nothing