我正在为Android制作一个互动故事编辑器。故事包含有关作者,其名称和一系列场景的信息:
weight = input ("Enter Weight: ")
if int(weight) <= 2:
rate = 1.10
elif int(weight) > 2 and int(weight) <= 10:
rate = 2.20
else:
rate = 3.70
charge = int(weight)*int(rate)
print (charge)
每个场景都包含有关其背景和一系列事物(元素)的信息:
public class Story {
public ArrayList<Scene> scenes;
private String author;
private String name;
public Story(){
scenes = new ArrayList<Scene>();
Scene s = new Scene(); /* Initializing a new story adds a first scene to it. */
this.add(s);
}
public void add(Scene s){ scenes.add(s); }
}
每件事情都有点复杂:
public class Scene {
private static final String DEFAULT_B = "#000000";
public ArrayList<Thing> things;
public String background;
Scene(){
things = new ArrayList<Thing>();
this.background = DEFAULT_B;
for(int i = 1; i <= 1000; i++){
Thing t = new Thing();
t.setText("Test " + i);
add(t);
}
}
public void add(Thing t){ things.add(t); }
}
这是在StoryView上绘制的:
public class Thing {
/* constants removed */
private float w;
private float h;
private float x;
private float y;
private String background_color;
private String text_color;
private String text;
Thing(){
/* initialize with constants */
}
/* getters and setters removed */
public void onTouch(double x, double y){
Toast.makeText(MainActivity.instance, "Clicked on Thing '" + this.text + "'", Toast.LENGTH_SHORT).show();
}
public RectF box(){
return new RectF(x, y, x+w, y+h);
}
public int resizeFrom(float x, float y){ /* try resizing */
for(RectF r: getResizerRects()){
if(inflatedRect(r, 15).contains(x, y)) return getResizerRects().indexOf(r);
}
return -1;
}
public void render(Canvas canvas, boolean sel){
Paint p = new Paint();
p.setAntiAlias(true);
RectF r = box();
p.setColor(Color.parseColor(background_color)); //todo res parser
canvas.drawRect(r, p);
p.setColor(Color.parseColor(text_color));
float font_size = 30.0f;
p.setTextSize(font_size);
Rect b = new Rect();
p.getTextBounds(text, 0, text.length(), b);
canvas.drawText(text, x + 10, y + 35, p);
p.setStyle(Paint.Style.STROKE);
p.setStrokeWidth(2);
p.setColor(Color.BLACK);
canvas.drawRect(r, p);
if(sel) drawResizers(canvas);
}
private ArrayList<RectF> getResizerRects(){
ArrayList<RectF> a = new ArrayList<>();
a.add(centerRect(x, y));
a.add(centerRect(x+w/2, y));
a.add(centerRect(x+w, y));
a.add(centerRect(x, y+h/2));
a.add(centerRect(x+w, y+h/2));
a.add(centerRect(x, y+h));
a.add(centerRect(x+w/2, y+h));
a.add(centerRect(x+w, y+h));
return a;
}
private RectF inflatedRect(RectF r, float d){
return new RectF(r.left - d, r.top - d, r.right + d*2, r.bottom + d*2);
}
private void drawResizers(Canvas c){
for(RectF r: getResizerRects()) drawResizer(c, r);
}
private RectF centerRect(float x, float y){
final float size = 14.0f;
return new RectF(x - size/2, y - size/2, x+size/2, y+size/2);
}
private void drawResizer(Canvas canvas, RectF r){
Paint paint = new Paint();
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.WHITE);
canvas.drawRect(r, paint);
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(2);
paint.setColor(Color.BLACK);
canvas.drawRect(r, paint);
}
}
从MainActivity调用哪个:
public class StoryView extends View{
private Story story;
private int scene;
private int selected_thing;
private int resize_corner;
private PointF click;
private Paint p;
private int width;
private int height;
public StoryView(Context context) {
super(context);
p = new Paint();
p.setAntiAlias(true);
this.story = null;
this.scene = 0;
this.selected_thing = -1;
this.resize_corner = -1;
this.click = new PointF();
this.setOnTouchListener(new View.OnTouchListener() {
@Override
public boolean onTouch(View v, MotionEvent event) {
StoryView.this.onTouch(event.getX(), event.getY(), event.getAction());
return true;
}
});
}
private void onTouch(float x, float y, int event){
Scene s = this.story.scenes.get(scene);
if(event == MotionEvent.ACTION_DOWN) {
boolean was_selected = false;
if(selected_thing != -1) resize_corner = s.things.get(selected_thing).resizeFrom(x, y);
if(resize_corner == -1) {
for (Thing t : s.things) {
if (t.box().contains(x, y)) {
t.onTouch(x, y);
was_selected = true;
selected_thing = s.things.indexOf(t);
click.x = x - t.getPosition().x;
click.y = y - t.getPosition().y;
}
}
}
if(!was_selected && resize_corner == -1) selected_thing = -1;
}
else if(event == MotionEvent.ACTION_MOVE){
if(selected_thing != -1){
if(resize_corner != -1){ // resize
if(resize_corner == 0){
RectF box = s.things.get(selected_thing).box();
box.left = x;
box.top = y;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 1){
RectF box = s.things.get(selected_thing).box();
box.top = y;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 2){
RectF box = s.things.get(selected_thing).box();
box.right = x;
box.top = y;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 3){
RectF box = s.things.get(selected_thing).box();
box.left = x;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 4){
RectF box = s.things.get(selected_thing).box();
box.right = x;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 5){
RectF box = s.things.get(selected_thing).box();
box.left = x;
box.bottom = y;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 6){
RectF box = s.things.get(selected_thing).box();
box.bottom = y;
s.things.get(selected_thing).setBox(box);
}
else if(resize_corner == 7){
RectF box = s.things.get(selected_thing).box();
box.right = x;
box.bottom = y;
s.things.get(selected_thing).setBox(box);
}
}
else s.things.get(selected_thing).setPosition(x-click.x, y-click.y); // move
}
}
else if(event == MotionEvent.ACTION_UP){
resize_corner = -1;
}
}
public void play(Story s){
this.story = s;
}
protected void onDraw(Canvas canvas){
super.onDraw(canvas);
Scene s = this.story.scenes.get(scene);
canvas.drawColor(Color.parseColor(s.background)); // todo: add a resource parser: background can be image or color
for (Thing t: s.things){
boolean sel = s.things.indexOf(t) == selected_thing;
t.render(canvas, sel);
}
update();
}
protected void update(){
invalidate();
}
protected void onSizeChanged(int w, int h, int _w, int _h){
super.onSizeChanged(w, h, _w, _h);
width = w;
height = h;
}
}
StoryManager使用Gson从文件加载/保存故事。 问题是,如果要绘制的东西太多(我尝试绘制1000),该应用程序将成为幻灯片,并显示在日志中:
public class MainActivity extends AppCompatActivity {
StoryView storyView;
public static MainActivity instance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
init();
}
private void init(){
instance = this;
requestWindowFeature(Window.FEATURE_NO_TITLE);
getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN,
WindowManager.LayoutParams.FLAG_FULLSCREEN);
storyView = new StoryView(this);
setContentView(storyView);
StoryManager.deleteStory("test");
StoryManager.createStory("test");
Story test = StoryManager.loadStory("test");
storyView.play(test);
}
}
I/Choreographer: Skipped 69 frames! The application may be doing too much work on its main thread.
I/Choreographer: Skipped 33 frames! The application may be doing too much work on its main thread.
I/art: Background sticky concurrent mark sweep GC freed 54541(1701KB) AllocSpace objects, 0(0B) LOS objects, 11% free, 13MB/15MB, paused 1.346ms total 100.998ms
也许有更有效的方法来渲染这些东西?如果有100件事,我没有错误和滞后。 编辑: Choreographer消息仍然出现在100件事上。