Android의 LinearLayout에 대해 설정할 속성이있어 자식 컨트롤을 적절하게 래핑 할 수 있습니까?
의미-자녀 수가 변경 가능하며 다음과 같이 수평으로 배치하고 싶습니다.
예 : Control1, Control2, Control3, ...
다음을 설정하여 수행합니다.
ll.setOrientation (LinearLayout.HORIZONTAL); foreach (어린이 c) ll.addView (c);
하지만 아이가 많으면 다음 줄로 넘어가는 대신 마지막 아이가 잘립니다.
이것이 어떻게 고칠 수 있는지 아십니까?
답변
2016 년 5 월 현재 Google은 FlexBoxLayout
귀하의 문제를 해결할 자체 를 만들었습니다 .
GitHub 저장소는 https://github.com/google/flexbox-layout 에서 찾을 수 있습니다.
답변
이것은 당신이 원하는 것입니다.
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
/**
*
* @author RAW
*/
public class FlowLayout extends ViewGroup {
private int line_height;
public static class LayoutParams extends ViewGroup.LayoutParams {
public final int horizontal_spacing;
public final int vertical_spacing;
/**
* @param horizontal_spacing Pixels between items, horizontally
* @param vertical_spacing Pixels between items, vertically
*/
public LayoutParams(int horizontal_spacing, int vertical_spacing) {
super(0, 0);
this.horizontal_spacing = horizontal_spacing;
this.vertical_spacing = vertical_spacing;
}
}
public FlowLayout(Context context) {
super(context);
}
public FlowLayout(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
assert (MeasureSpec.getMode(widthMeasureSpec) != MeasureSpec.UNSPECIFIED);
final int width = MeasureSpec.getSize(widthMeasureSpec) - getPaddingLeft() - getPaddingRight();
int height = MeasureSpec.getSize(heightMeasureSpec) - getPaddingTop() - getPaddingBottom();
final int count = getChildCount();
int line_height = 0;
int xpos = getPaddingLeft();
int ypos = getPaddingTop();
int childHeightMeasureSpec;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST);
} else {
childHeightMeasureSpec = MeasureSpec.makeMeasureSpec(0, MeasureSpec.UNSPECIFIED);
}
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
child.measure(MeasureSpec.makeMeasureSpec(width, MeasureSpec.AT_MOST), childHeightMeasureSpec);
final int childw = child.getMeasuredWidth();
line_height = Math.max(line_height, child.getMeasuredHeight() + lp.vertical_spacing);
if (xpos + childw > width) {
xpos = getPaddingLeft();
ypos += line_height;
}
xpos += childw + lp.horizontal_spacing;
}
}
this.line_height = line_height;
if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.UNSPECIFIED) {
height = ypos + line_height;
} else if (MeasureSpec.getMode(heightMeasureSpec) == MeasureSpec.AT_MOST) {
if (ypos + line_height < height) {
height = ypos + line_height;
}
}
setMeasuredDimension(width, height);
}
@Override
protected ViewGroup.LayoutParams generateDefaultLayoutParams() {
return new LayoutParams(1, 1); // default of 1px spacing
}
@Override
protected android.view.ViewGroup.LayoutParams generateLayoutParams(
android.view.ViewGroup.LayoutParams p) {
return new LayoutParams(1, 1, p);
}
@Override
protected boolean checkLayoutParams(ViewGroup.LayoutParams p) {
if (p instanceof LayoutParams) {
return true;
}
return false;
}
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
final int count = getChildCount();
final int width = r - l;
int xpos = getPaddingLeft();
int ypos = getPaddingTop();
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
final int childw = child.getMeasuredWidth();
final int childh = child.getMeasuredHeight();
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (xpos + childw > width) {
xpos = getPaddingLeft();
ypos += line_height;
}
child.layout(xpos, ypos, xpos + childw, ypos + childh);
xpos += childw + lp.horizontal_spacing;
}
}
}
}
및 XML 파일
/* you must write your package name and class name */
<org.android.FlowLayout
android:id="@+id/flow_layout"
android:layout_marginLeft="5dip"
android:layout_width="fill_parent"
android:layout_height="wrap_content"/>
답변
이런 종류의 행동이 필요한 사람을 위해 :
private void populateLinks(LinearLayout ll, ArrayList<Sample> collection, String header) {
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth() - 10;
if (collection.size() > 0) {
LinearLayout llAlso = new LinearLayout(this);
llAlso.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
llAlso.setOrientation(LinearLayout.HORIZONTAL);
TextView txtSample = new TextView(this);
txtSample.setText(header);
llAlso.addView(txtSample);
txtSample.measure(0, 0);
int widthSoFar = txtSample.getMeasuredWidth();
for (Sample samItem : collection) {
TextView txtSamItem = new TextView(this, null,
android.R.attr.textColorLink);
txtSamItem.setText(samItem.Sample);
txtSamItem.setPadding(10, 0, 0, 0);
txtSamItem.setTag(samItem);
txtSamItem.setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
TextView self = (TextView) v;
Sample ds = (Sample) self.getTag();
Intent myIntent = new Intent();
myIntent.putExtra("link_info", ds.Sample);
setResult("link_clicked", myIntent);
finish();
}
});
txtSamItem.measure(0, 0);
widthSoFar += txtSamItem.getMeasuredWidth();
if (widthSoFar >= maxWidth) {
ll.addView(llAlso);
llAlso = new LinearLayout(this);
llAlso.setLayoutParams(new LayoutParams(
LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
llAlso.setOrientation(LinearLayout.HORIZONTAL);
llAlso.addView(txtSamItem);
widthSoFar = txtSamItem.getMeasuredWidth();
} else {
llAlso.addView(txtSamItem);
}
}
ll.addView(llAlso);
}
}
답변
오래된 질문이지만 누군가가 여기에 도착할 경우 정확히 그렇게하는 두 개의 라이브러리가 있습니다.
https://github.com/blazsolar/FlowLayout
https://github.com/ApmeM/android-flowlayout
답변
유사하지만 더 간단한 문제에 대한 해결책을 찾고 있습니다. 즉, 하위 텍스트 콘텐츠를 가로 레이아웃으로 래핑하는 것입니다. kape123의 솔루션이 잘 작동합니다. 그러나 ClickableSpan을 사용하여이 문제에 대한 더 간단한 것을 찾으십시오. 간단한 경우에 유용 할 수 있습니다. 단편:
String[] stringSource = new String[sourceList.size()];
for (int i = 0; c < sourceList.size(); i++) {
String text = sourceList.get(i);
stringSource[i] = text;
}
SpannableString totalContent = new SpannableString(TextUtils.join(",", stringSource));
int start = 0;
for (int j = 0; j < stringSource.length(); j++) {
final String text = stringSource[j];
ClickableSpan span = new ClickableSpan() {
@Override
public void updateDrawState(TextPaint ds) {
ds.setUnderlineText(true);
ds.setColor(getResources().getColor(R.color.green));
}
@Override
public void onClick(View widget) {
// the text clicked
}
};
int end = (start += text.length());
totalContent.setSpan(span, start, end, 0);
star = end + 1;
}
TextView wrapperView = (TextView) findViewById(horizontal_container_id);
wrapperView.setMovementMethod(LinkMovementMethod.getInstance());
wrapperView.setText(totalContent, BufferType.SPANNABLE);
}
답변
Randy Sugianto ‘Yuku ‘s answer 의 코드 수정 버전 과 내가 마침내 함께했던 것 :
import android.content.Context
import android.util.AttributeSet
import android.view.View
import android.view.View.MeasureSpec.*
import android.view.ViewGroup
import androidx.core.content.withStyledAttributes
import androidx.core.view.children
import *.*.*.R
class FlowLayout(context: Context, attributeSet: AttributeSet) : ViewGroup(context, attributeSet) {
private var lineHeight: Int = 0
private var horizontalSpacing = 0F
private var verticalSpacing = 0F
init {
context.withStyledAttributes(attributeSet, R.styleable.FlowLayout) {
horizontalSpacing = getDimension(R.styleable.FlowLayout_horizontalSpacing, 0F)
verticalSpacing = getDimension(R.styleable.FlowLayout_verticalSpacing, 0F)
}
}
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
val width = getSize(widthMeasureSpec) - paddingLeft - paddingRight
var height = getSize(heightMeasureSpec) - paddingTop - paddingBottom
var xPosition = paddingLeft
var yPosition = paddingTop
val childHeightMeasureSpec = makeMeasureSpec(
height, if (getMode(heightMeasureSpec) == AT_MOST) AT_MOST else UNSPECIFIED
)
children.forEach { child ->
if (child.visibility != GONE) {
val layoutParams = child.layoutParams as LayoutParamsWithSpacing
child.measure(makeMeasureSpec(width, AT_MOST), childHeightMeasureSpec)
val childWidth = child.measuredWidth
lineHeight =
Math.max(lineHeight, child.measuredHeight + layoutParams.verticalSpacing)
if (xPosition + childWidth > width) {
xPosition = paddingLeft
yPosition += lineHeight
}
xPosition += childWidth + layoutParams.horizontalSpacing
}
}
if (getMode(heightMeasureSpec) == UNSPECIFIED ||
getMode(heightMeasureSpec) == AT_MOST && yPosition + lineHeight < height
) {
height = yPosition + lineHeight
}
setMeasuredDimension(width, height)
}
override fun onLayout(changed: Boolean, left: Int, top: Int, right: Int, bottom: Int) {
val width = right - left
var xPosition = paddingLeft
var yPosition = paddingTop
children.forEach { child ->
if (child.visibility != View.GONE) {
val layoutParams = child.layoutParams as LayoutParamsWithSpacing
val childWidth = child.measuredWidth
if (xPosition + childWidth > width) {
xPosition = paddingLeft
yPosition += lineHeight
}
child.layout(
xPosition, yPosition, xPosition + childWidth,
yPosition + child.measuredHeight
)
xPosition += layoutParams.horizontalSpacing
xPosition += childWidth
}
}
}
override fun generateDefaultLayoutParams(): ViewGroup.LayoutParams =
LayoutParamsWithSpacing(1, 1)
override fun generateLayoutParams(layoutParams: LayoutParams) =
LayoutParamsWithSpacing(horizontalSpacing.toInt(), verticalSpacing.toInt())
override fun checkLayoutParams(layoutParams: LayoutParams) =
layoutParams is LayoutParamsWithSpacing
class LayoutParamsWithSpacing(val horizontalSpacing: Int, val verticalSpacing: Int) :
ViewGroup.LayoutParams(0, 0)
}
style / attrs.xml 파일에서 :
<resources>
<declare-styleable name="FlowLayout">
<attr name="horizontalSpacing" format="dimension" />
<attr name="verticalSpacing" format="dimension" />
</declare-styleable>
</resources>
용법:
<*.*.*.*.FlowLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:horizontalSpacing="8dp"
app:verticalSpacing="8dp">
<!-- ... -->
</*.*.*.*.FlowLayout>
답변
//this method will add image view to liner grid and warp it if no space in new child LinearLayout grid
private void addImageToLinyerLayout(LinearLayout ll , ImageView v)
{
//set the padding and margin and weight
v.setPadding(5, 5, 5, 5);
Display display = getWindowManager().getDefaultDisplay();
int maxWidth = display.getWidth() - 10;
int maxChildeNum = (int) ( maxWidth / (110)) ;
Toast.makeText(getBaseContext(), "c" + v.getWidth() ,
Toast.LENGTH_LONG).show();
//loop through all child of the LinearLayout
for (int i = 0; i < ll.getChildCount(); i++) {
View chidv = ll.getChildAt(i);
Class c = chidv.getClass();
if (c == LinearLayout.class) {
//here we are in the child lay out check to add the imageView if there is space
//Available else we will add it to new linear layout
LinearLayout chidvL = (LinearLayout)chidv;
if(chidvL.getChildCount() < maxChildeNum)
{
chidvL.addView(v);
return;
}
} else{
continue;
}
}
//if you reached here this means there was no roam for adding view so we will
//add new linear layout
LinearLayout childLinyer = new LinearLayout(this);
childLinyer.setLayoutParams(new LayoutParams(LayoutParams.FILL_PARENT,
LayoutParams.WRAP_CONTENT));
childLinyer.setOrientation(LinearLayout.HORIZONTAL);
ll.addView(childLinyer);
childLinyer.addView(v);
}
위의 방법은 agrid 및 레이아웃과 같이 imgeview를 나란히 추가합니다.
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="vertical"
android:id="@+id/imageslayout"
></LinearLayout>
이 솔루션을 게시하면 도움이 될 수 있고 한 번만 절약하고 내 앱에서 사용합니다.