Android 屏幕适配最佳实践

参考该文章理论知识加代码

Android 屏幕适配方案

但是呢,该篇博文里个人觉得代码封装的不是很好,于是自己封装了下,使用XStream生成xml。上面那篇文章里没有对横竖屏进行适配,代码里完善了这一点,对横竖屏进行了适配。

在开始码代码前,贴一张图,结合前面那篇文章的理论知识一起看。

然后呢看最终适配的效果,这里以320*480为基准,屏幕上放一个TextView,宽度为x160,高度为y240,效果图如下

然后呢,不要惊讶,你会发现里面的两个pad并没有适配,其实呢,我也母鸡呀,但是我开了一个模拟器,启动了一个pad,其实是适配了。于是就没有然后了,有兴趣的再研究下吧。

先封装Screen类

package cn.edu.zafu.model;

/**
 * @author lizhangqu
 * @description
 * @date
 */
public class Screen {
    private int width;
    private int height;

    public Screen(int width, int height) {
        this.width = width;
        this.height = height;

    }

    public int getWidth() {
        return width;
    }

    public void setWidth(int width) {
        this.width = width;
    }

    public int getHeight() {
        return height;
    }

    public void setHeight(int height) {
        this.height = height;
    }

    public String getDir(boolean portrait) {
        // landscape是横向,portrait是纵向
        if (portrait) {
            return String.format("values-%dx%d", height, width);
        } else {
            return String.format("values-land-%dx%d", height, width);
        }
    }

    @Override
    public String toString() {
        return "Screen [width=" + width + ", height=" + height + "]";
    }

}

其次是Rescource类,使用注解

package cn.edu.zafu.model;

import java.util.ArrayList;
import java.util.List;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamImplicit;

/**
 * @author lizhangqu
 * @description
 * @date
 */
@XStreamAlias("resources")
public class Resource {
    @XStreamImplicit(itemFieldName = "dimen")
    List<Dimen> dimens = new ArrayList<Dimen>();

    public Resource() {
    }

    public Resource(List<Dimen> dimens) {
        this.dimens = dimens;
    }

    public List<Dimen> getDimens() {
        return dimens;
    }

    public void setDimens(List<Dimen> dimens) {
        this.dimens = dimens;
    }

    @Override
    public String toString() {
        return "Resource [dimens=" + dimens + "]";
    }

}

Dimen类,依然使用注解

package cn.edu.zafu.model;

import com.thoughtworks.xstream.annotations.XStreamAlias;
import com.thoughtworks.xstream.annotations.XStreamAsAttribute;
import com.thoughtworks.xstream.annotations.XStreamConverter;
import com.thoughtworks.xstream.converters.extended.ToAttributedValueConverter;

/**
 * @author lizhangqu
 * @description
 * @date
 */
@XStreamAlias("dimen")
@XStreamConverter(value = ToAttributedValueConverter.class, strings = { "value" })
public class Dimen {
    @XStreamAlias("name")
    @XStreamAsAttribute()
    private String name;
    private String value;

    public Dimen() {
    }

    public Dimen(String name, String value) {
        this.name = name;
        this.value = value;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Dimen [name=" + name + ", value=" + value + "]";
    }

}

继承XStream类,默认的只会输出xml体,我们加入xml头

<?xml version="1.0" encoding="utf-8"?>
package cn.edu.zafu.util;

import java.io.OutputStream;
import java.io.Writer;

import com.thoughtworks.xstream.XStream;

/**
 * @author lizhangqu
 * @description
 * @date
 */
public class XmlDeclarationXStream extends XStream {
    private String xmlDeclaration;
    private String version;
    private String ecoding;

    public XmlDeclarationXStream() {
        this("1.0", "utf-8");
    }

    public XmlDeclarationXStream(String version, String ecoding) {
        this.version = version;
        this.ecoding = ecoding;
        buildDeclaration();

    }

    private void buildDeclaration() {
        // generate xmlDeclaration
        StringBuffer buffer = new StringBuffer();
        xmlDeclaration = buffer.append("<?xml version=\"").append(this.version)
                .append("\" encoding=\"").append(this.ecoding).append("\"?>")
                .append("\n").toString();
        buffer = null;
    }

    public String getDeclaration() {
        return xmlDeclaration;
    }

    @Override
    public void toXML(Object arg0, OutputStream arg1) {
        try {
            String dec = this.getDeclaration();
            byte[] bytesOfDec = dec.getBytes(this.ecoding);
            arg1.write(bytesOfDec);
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.toXML(arg0, arg1);
    }

    @Override
    public void toXML(Object arg0, Writer arg1) {
        try {
            arg1.write(getDeclaration());
        } catch (Exception e) {
            e.printStackTrace();
        }
        super.toXML(arg0, arg1);
    }

}

最后是生成资源文件的工具类,见注释

package cn.edu.zafu.util;

import java.io.BufferedWriter;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStreamWriter;
import java.text.DecimalFormat;
import java.util.List;

import cn.edu.zafu.model.Dimen;
import cn.edu.zafu.model.Resource;
import cn.edu.zafu.model.Screen;

import com.thoughtworks.xstream.XStream;

/**
 *
 * @author lizhangqu
 * @description a tool to generate what we want
 * @date
 */
public class Generator {
    // default base width
    private static final int DEFAULT_BASE_WIDTH = 320;
    // default base height
    private static final int DEFAULT_BASE_HEIGHT = 480;
    // decimal formator
    private static final DecimalFormat DECIMAL_FORMAT = new DecimalFormat(
            "#.##");
    // a xstream,XmlDeclarationXStream extends XStream
    private static final XStream XSTREAM = new XmlDeclarationXStream();
    //res dir
    private File resFile=null;
    // base width
    private int baseWidth;
    // base height
    private int beseHeight;

    /**
     * using default width and height to generate default width is 320,default
     * height is 480
     */
    public Generator() {
        this(DEFAULT_BASE_WIDTH, DEFAULT_BASE_HEIGHT);
    }

    /**
     * using baseWidth and baseHeight to generator
     *
     * @param baseWidth
     * @param beseHeight
     */
    public Generator(int baseWidth, int beseHeight) {
        this.baseWidth = baseWidth;
        this.beseHeight = beseHeight;
        XSTREAM.autodetectAnnotations(true);
        this.resFile = new File("./res");
        if (!resFile.exists()) {
            resFile.mkdir();
        }
    }

    /**
     * using w and h to generate xml
     *
     * @param w
     *            screen width
     * @param h
     *            screen height
     * @return generated xml
     */
    public String generateXml(Screen screen) {
        Resource resource = new Resource();
        List<Dimen> dimens = resource.getDimens();

        float cellWidth = screen.getWidth() * 1.0f / baseWidth;
        float cellHeight = screen.getHeight() * 1.0f / beseHeight;

        String result = null;
        Dimen dimen = null;
        for (int i = 1; i <= baseWidth; i++) {
            result = DECIMAL_FORMAT.format(i * cellWidth);
            dimen = new Dimen();
            dimen.setName(String.format("x%d", i));
            dimen.setValue(String.format("%spx", result));
            dimens.add(dimen);
        }

        for (int i = 1; i <= beseHeight; i++) {
            result = DECIMAL_FORMAT.format(i * cellHeight);
            dimen = new Dimen();
            dimen.setName(String.format("y%d", i));
            dimen.setValue(String.format("%spx", result));
            dimens.add(dimen);
        }
        String xml = XSTREAM.toXML(resource);
        return xml;
    }
    public String generateXmlLandscape(Screen screen) {
        Screen s=new Screen(screen.getHeight(),screen.getWidth());
        return generateXml(s);
    }
    /**
     * write xmlContent to a File
     *
     * @param screen
     * @param xmlContent
     */
    public void write2File(String valuesPath, String xmlContent) {
        File fileDir = new File(this.resFile + File.separator + valuesPath);
        fileDir.mkdir();
        File file = new File(fileDir.getAbsolutePath(), "dimens.xml");
        BufferedWriter bw = null;
        FileOutputStream fos = null;
        try {
            fos = new FileOutputStream(file);
            bw = new BufferedWriter(new OutputStreamWriter(fos));
            bw.write(xmlContent);
        } catch (IOException e) {
            e.printStackTrace();
        }  finally {
            try {
                if (bw != null) {
                    bw.close();
                    bw = null;
                }
                if (fos != null) {
                    fos.close();
                    fos = null;
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

主函数,生成常见分辨率的资源文件

package cn.edu.zafu;

import java.util.ArrayList;
import java.util.List;

import cn.edu.zafu.model.Screen;
import cn.edu.zafu.util.Generator;

/**
 * @author lizhangqu
 * @description
 * @date
 */
public class Main {
    public static void main(String[] args) {
        new Main().bulid();
    }

    public void bulid() {
        Generator generator = new Generator(320, 480);
        List<Screen> screens = new ArrayList<Screen>();
        Screen screen = null;

        screen = new Screen(320, 400);
        screens.add(screen);
        screen = new Screen(320, 480);
        screens.add(screen);
        screen = new Screen(480, 800);
        screens.add(screen);
        screen = new Screen(480, 854);
        screens.add(screen);
        screen = new Screen(540, 960);
        screens.add(screen);
        screen = new Screen(600, 1024);
        screens.add(screen);
        screen = new Screen(720, 1184);
        screens.add(screen);
        screen = new Screen(720, 1196);
        screens.add(screen);
        screen = new Screen(720, 1280);
        screens.add(screen);
        screen = new Screen(768, 1024);
        screens.add(screen);
        screen = new Screen(768, 1280);
        screens.add(screen);
        screen = new Screen(800, 1280);
        screens.add(screen);
        screen = new Screen(1080, 1812);
        screens.add(screen);
        screen = new Screen(1080, 1920);
        screens.add(screen);
        screen = new Screen(1200, 1920);
        screens.add(screen);
        screen = new Screen(1440, 2560);
        screens.add(screen);
        screen = new Screen(2048, 1536);
        screens.add(screen);
        screen = new Screen(2560, 1600);
        screens.add(screen);
        int size = screens.size();
        for (int i = 0; i < size; i++) {
            String portrait = generator.generateXml(screens.get(i));
            generator.write2File(screens.get(i).getDir(true), portrait);

            String landscape = generator.generateXmlLandscape(screens.get(i));
            generator.write2File(screens.get(i).getDir(false), landscape);

            System.out.println("create file "+i+" success");

        }
        System.out.println("success");
    }

}

源码下载

github下载:AndroidScreenAdapter

csdn下载:AndroidScreenAdapter

时间: 2024-09-30 16:54:38

Android 屏幕适配最佳实践的相关文章

【转】Android屏幕适配全攻略(最权威的官方适配指导)

Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持各种屏幕尺寸 使用wrap_contentmatch_parentweight 使用相对布局

Android屏幕适配全攻略(最权威的官方适配指导)

Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配. 由于Android系统的开放性,任何用户.开发者.OEM厂商.运营商都可以对Android进行定制,修改成他们想要的样子. 但是这种"碎片化"到底到达什么程度呢? 在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告,统计数据表明, 2012年,支持Android的设备共有3997种. 2013年,支持Android的设备

Android屏幕适配全攻略(最权威的Google官方适配指导)

Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! 出处:http://blog.csdn.net/zhaokaiqiang1992 Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持各种屏幕尺

Android屏幕适配全攻略(最权威的官方适配指导)(转),共大家分享。

Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持各种屏幕尺寸 使用wrap_contentmatch_parentweight 使用相对布局

(转)Android屏幕适配全攻略

转载自http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持各种屏幕尺

Android屏幕适配全攻略(最权威的官方适配指导)--转

本文转自:http://www.cocoachina.com/android/20151030/13971.html Android屏幕适配出现的原因 在我们学习如何进行屏幕适配之前,我们需要先了解下为什么Android需要进行屏幕适配. 由于Android系统的开放性,任何用户.开发者.OEM厂商.运营商都可以对Android进行定制,修改成他们想要的样子. 但是这种“碎片化”到底到达什么程度呢? 在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告

【Android开发进阶】Android屏幕适配全攻略(最权威的官方适配指导)

转载请注明出处:http://blog.csdn.net/zhaokaiqiang1992 Android的屏幕适配一直以来都在折磨着我们这些开发者,本篇文章以Google的官方文档为基础,全面而深入的讲解了Android屏幕适配的原因.重要概念.解决方案及最佳实践,我相信如果你能认真的学习本文,对于Android的屏幕适配,你将有所收获! Android屏幕适配出现的原因 重要概念 屏幕尺寸 屏幕分辨率 屏幕像素密度 dpdipdpisppx mdpihdpixdpixxdpi 解决方案 支持

Android开发:最全面、最易懂的Android屏幕适配解决方案

前言 Android的屏幕适配一直以来都在折磨着我们Android开发者,本文将结合: Google的官方权威适配文档 郭霖:Android官方提供的支持不同屏幕大小的全部方法 Stormzhang:Android 屏幕适配 鸿洋:Android 屏幕适配方案 凯子:Android屏幕适配全攻略(最权威的官方适配指导) 自身的思考&实践 给你带来一种全新.全面而逻辑清晰的Android屏幕适配思路,只要你认真阅读,保证你能解决Android的屏幕适配问题! 目录 定义 使得某一元素在Androi

Android屏幕适配攻略

Android适配攻略 一.屏幕适配的必要性 为什么Android需要适配? 由于Android系统的开放性,任何用户.开发者.OEM厂商.运营商都可以对Android进行定制,修改成他们想要的样子. 但是这种"碎片化"到底到达什么程度呢? 在2012年,OpenSignalMaps(以下简称OSM)发布了第一份Android碎片化报告,统计数据表明, 2012年,支持Android的设备共有3997种. 2013年,支持Android的设备共有11868种. 2014年,支持Andr