我正在尝试以编程方式(不使用XML文件)在Android中创建自定义子视图(这就是我在iOS中所称的),这基本上是一些基本视图(标签,按钮,文本字段等)放在一个可重复使用的子视图类中,这样我就可以在Android UIViewControllers
或Activity
中使用它。
我不知道Android中的正确术语是什么。似乎有一百万种不同的术语。
自定义视图,ViewGroups,布局,窗口小部件,组件,以及您想要调用它的任何内容。
在iOS中,这样做就是这样:
@interface CustomView : UIView
@property (nonatomic, strong) UILabel *message;
@property (nonatomic, strong) UIButton *button;
@end
@implementation CustomView
-(id)initWithFrame:(CGRect)frame
{
self = [super initWithFrame:frame];
if(self)
{
[self initViews];
[self initConstraints];
}
return self;
}
-(void)initViews
{
self.message = [[UILabel alloc] init];
self.button = [[UIButton alloc] init];
[self addSubview:self.message];
[self addSubview:self.button];
}
-(void)initConstraints
{
id views = @{
@"message": self.message,
@"button": self.button
};
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[message]|" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|[button]|" options:0 metrics:nil views:views]];
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:|[message][button]|" options:0 metrics:nil views:views]];
}
@end
现在,我可以在我选择的任何ViewController(Android Activity
)中重复使用此自定义视图。
如何在Android中实现类似的效果?
我一直在环顾四周,从Android收集的内容中添加子视图,我将它们添加到Layouts
:
RelativeLayout relativeLayout = new RelativeLayout(...);
TextView textView = new TextView(...);
relativeLayout.addSubview(textView);
这是否意味着我需要扩展RelativeLayout
或ViewGroup
?
查看此页面:http://developer.android.com/reference/android/view/ViewGroup.html
似乎我们需要编写一些非常复杂的逻辑来布局自定义视图,例如:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int count = getChildCount();
// These keep track of the space we are using on the left and right for
// views positioned there; we need member variables so we can also use
// these for layout later.
mLeftWidth = 0;
mRightWidth = 0;
// Measurement will ultimately be computing these values.
int maxHeight = 0;
int maxWidth = 0;
int childState = 0;
// Iterate through all children, measuring them and computing our dimensions
// from their size.
for (int i = 0; i < count; i++) {
final View child = getChildAt(i);
if (child.getVisibility() != GONE) {
// Measure the child.
measureChildWithMargins(child, widthMeasureSpec, 0, heightMeasureSpec, 0);
// Update our size information based on the layout params. Children
// that asked to be positioned on the left or right go in those gutters.
final LayoutParams lp = (LayoutParams) child.getLayoutParams();
if (lp.position == LayoutParams.POSITION_LEFT) {
mLeftWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else if (lp.position == LayoutParams.POSITION_RIGHT) {
mRightWidth += Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
} else {
maxWidth = Math.max(maxWidth,
child.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
}
maxHeight = Math.max(maxHeight,
child.getMeasuredHeight() + lp.topMargin + lp.bottomMargin);
childState = combineMeasuredStates(childState, child.getMeasuredState());
}
}
// Total width is the maximum width of all inner children plus the gutters.
maxWidth += mLeftWidth + mRightWidth;
// Check against our minimum height and width
maxHeight = Math.max(maxHeight, getSuggestedMinimumHeight());
maxWidth = Math.max(maxWidth, getSuggestedMinimumWidth());
// Report our final dimensions.
setMeasuredDimension(resolveSizeAndState(maxWidth, widthMeasureSpec, childState),
resolveSizeAndState(maxHeight, heightMeasureSpec,
childState << MEASURED_HEIGHT_STATE_SHIFT));
}
我想要做的就是在自定义视图中使用多个基本的Android标签,视图,按钮,如上面的iOS示例,为什么在Android中这么难?
我希望这样简单:
public class CustomView extends View
{
public RelativeLayout mainLayout;
public TextView message;
public Button button;
// default constructor
public CustomView()
{
...
initViews();
initLayouts();
addViews();
}
public initViews()
{
mainLayout = new RelativeLayout(this);
message = new TextView(this);
button = new Button(this);
...
}
public initLayouts()
{
// --------------------------------------------------
// use Android layout params to position subviews
// within this custom view class
// --------------------------------------------------
}
public addViews()
{
mainLayout.addView(message);
mainLayout.addView(button);
setContentView(mainLayout);
}
}
对不起,我真诚地想要学习和构建一个基本的Android应用程序而不是试图压制Android的做事方式。
我知道如何在Activity中添加和布局子视图,并且过去两天一直这样做,但不是在自定义视图/视图组/布局中。我不想最终为Android应用中的每个Activity构建完全相同的子视图,这恰好违背了良好的编码习惯吗? :d
只需从其他已完成iOS和Android开发的人那里获得一些指导。
似乎我正在寻找的是一个复合控制:http://developer.android.com/guide/topics/ui/custom-components.html
我会继续挖掘并希望达到我追求的结果:D
只需要解决这个Inflater业务。
答案 0 :(得分:1)
好吧,我想我明白了,不确定它是否是最好的解决方案,但它能做到我想要的。
所以它是这样的:
public class CustomView extends RelativeLayout
{
private Context context;
public TextView message;
public Button button;
public CustomView(Context context)
{
super(context);
// ---------------------------------------------------------
// store context as I like to create the views inside
// initViews() method rather than in the constructor
// ---------------------------------------------------------
this.context = context;
initViews();
initLayouts();
addViews();
}
public CustomView(Context context, AttributeSet attrs)
{
super(context, attrs);
// ---------------------------------------------------------
// store context as I like to create the views inside
// initViews() method rather than in the constructor
// ---------------------------------------------------------
this.context = context;
initViews();
initLayouts();
addViews();
}
public initViews()
{
// ----------------------------------------
// note "context" refers to this.context
// that we stored above.
// ----------------------------------------
message = new TextView(context);
...
button = new Button(context);
...
}
public initLayouts()
{
// --------------------------------------------------
// use Android layout params to position subviews
// within this custom view class
// --------------------------------------------------
message.setId(View.generateViewId());
button.setId(View.generateViewId());
RelativeLayout.LayoutParams messageLayoutParams = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.MATCH_PARENT
);
message.setLayoutParams(messageLayoutParams);
RelativeLayout.LayoutParams buttonLayoutParams = new RelativeLayout.LayoutParams(
LayoutParams.MATCH_PARENT,
LayoutParams.WRAP_CONTENT
);
button.setLayoutParams(buttonLayoutParams);
}
public addViews()
{
// adding subviews to layout
addView(message);
addView(button);
}
}
现在,我可以在我的任何活动中使用此自定义视图:
public class MainActivity extends ActionBarActivity {
// custom view instance
protected CustomView approvalView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
...
initViews();
}
public initViews()
{
...
approvalView = new CustomView(this);
approvalView.message.setText("1 + 1 = 2");
approvalView.button.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
Log.d("Logger", "Math formula approved! :D");
}
});
}
}
如果我们使用XML创建布局而使用Inflater,这不是我喜欢做的事情,所以我以编程方式生成了我的视图布局:D
“extendLayout”中的上述“RelativeLayout”当然可以替换为“LinearLayout”或其他布局。
答案 1 :(得分:1)
为这个问题的一般访问者添加一个简单的答案......
您无法像使用iOS EditingDomain
一样向Android View
添加子视图。
如果您需要在Android中添加子视图,请使用其中一个UIView
子类(例如ViewGroup
,LinearLayout
,甚至是您自己的自定义子类。)
RelativeLayout